Call Libraries

library(tidyverse)
library(car)
library(moments)
library(glmnet)

Calling the Transformed Datasets

income_cleaned = read_csv('Shiny_app/data/income_cleaned.csv')
Rows: 1921 Columns: 5── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Name, Group
dbl (3): Year, Num, Avg
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
industry_cleaned = read_csv('Shiny_app/data/industry_cleaned.csv')
Rows: 2476 Columns: 5── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Name, Group
dbl (3): Year, Num, Avg
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Creating the Models

sat.model.summary <- function (df, field, sat.formula){
    
    #Shapiro-Wilks test to evaluate normality
    print(shapiro.test(df[[field]]))
    
    #Kurtosis evaluation (normal distribution has a value close to 3)
    print('kurtosis')
    print(kurtosis(df[[field]]))
    linear.model.cleaned = lm(sat.formula, data = df)
    print(summary(linear.model.cleaned))
    plot(linear.model.cleaned)
    
    #histograms of response variable to check distribution
    print(df %>% 
      ggplot(aes_string(field)) + 
      geom_histogram() + 
      labs(title = 'Average Credit Amount Distribution') + 
      theme(plot.title = element_text(hjust = 0.5)))
    
    #Checking multicollinearity using VIF measurement
    print(vif(linear.model.cleaned))
    influencePlot(linear.model.cleaned)
    #avPlots(linear.model.cleaned)
}


sat.formula <- Avg ~ .
sat.field <- 'Avg'

sat.model.summary(income_cleaned, sat.field, sat.formula)

    Shapiro-Wilk normality test

data:  df[[field]]
W = 0.17297, p-value < 2.2e-16

[1] "kurtosis"
[1] 169.7518

Call:
lm(formula = sat.formula, data = df)

Residuals:
      Min        1Q    Median        3Q       Max 
-11338570   -547702     94139    421302  87181761 

Coefficients:
                                                                                                Estimate Std. Error t value Pr(>|t|)    
(Intercept)                                                                                   -1.157e+08  5.512e+07  -2.100  0.03590 *  
Year                                                                                           5.721e+04  2.731e+04   2.095  0.03634 *  
NameAlternative Fuels and Electric Vehicle Recharging Property Credit                         -3.287e+05  1.242e+06  -0.265  0.79140    
NameAlternative Minimum Tax Credit                                                             6.538e+05  9.757e+05   0.670  0.50286    
NameBeer Production Credit                                                                     3.316e+05  1.290e+06   0.257  0.79715    
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 6/23/08 but before 7/1/15  1.429e+06  9.960e+05   1.434  0.15162    
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 7/1/15                     4.098e+06  1.421e+06   2.883  0.00398 ** 
NameBrownfield Tax Credits - Redevelopment Tax Credit - Prior to 6/23/08                       1.182e+06  9.927e+05   1.191  0.23386    
NameBrownfield Tax Credits - Remediation Real Property Tax Credit                             -7.587e+04  9.920e+05  -0.076  0.93904    
NameClean Heating Fuel Credit                                                                  7.148e+04  1.024e+06   0.070  0.94436    
NameConservation Easement Tax Credit                                                           1.143e+05  1.064e+06   0.107  0.91444    
NameCredit for Employment of Persons with Disabilities                                        -9.343e+05  1.119e+06  -0.835  0.40391    
NameCredit for Purchase of an Automated External Defibrillator                                -1.449e+05  9.695e+05  -0.150  0.88117    
NameCredit for Taxicabs & Livery Service Vehicles Accessible to Persons with Disabilities      2.316e+05  1.779e+06   0.130  0.89645    
NameEmpire State Apprentice Tax Credit                                                        -7.983e+05  1.524e+06  -0.524  0.60040    
NameEmpire State Commercial Production Credit                                                  2.183e+05  1.291e+06   0.169  0.86576    
NameEmpire State Film Post Production Credit                                                   2.521e+04  1.049e+06   0.024  0.98082    
NameEmpire State Film Production Credit                                                        1.145e+07  9.967e+05  11.485  < 2e-16 ***
NameEmpire State Musical and Theatrical Production Credit                                     -2.342e+05  1.775e+06  -0.132  0.89507    
NameExcelsior Jobs Program Credit                                                              1.035e+05  9.545e+05   0.108  0.91366    
NameEZ/QEZE Tax Credits - EZ Investment Tax Credit                                             2.752e+06  8.862e+05   3.105  0.00193 ** 
NameEZ/QEZE Tax Credits - EZ Wage Tax Credit                                                   4.845e+05  9.213e+05   0.526  0.59899    
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes                                  1.245e+06  9.239e+05   1.348  0.17785    
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes For Corporate Partners          -1.025e+05  9.549e+05  -0.107  0.91455    
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit                                           -6.145e+04  9.387e+05  -0.065  0.94781    
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit For Corporate Partners                     9.119e+04  1.044e+06   0.087  0.93038    
NameFarm Workforce Retention Credit                                                           -7.802e+03  1.285e+06  -0.006  0.99516    
NameFarmers' School Tax Credit                                                                 1.440e+05  1.021e+06   0.141  0.88786    
NameHire a Veteran Credit                                                                     -1.238e+06  1.782e+06  -0.695  0.48721    
NameHistoric Properties Rehabilitation Credit                                                  1.352e+06  1.055e+06   1.282  0.20015    
NameIndustrial or Manufacturing Business Tax Credit                                            4.997e+05  1.074e+06   0.465  0.64173    
NameInvestment Tax Credit                                                                      4.463e+05  8.895e+05   0.502  0.61588    
NameInvestment Tax Credit for the Financial Services Industry                                  3.976e+05  1.008e+06   0.395  0.69325    
NameLife Sciences Research & Development Tax Credit                                           -8.207e+04  2.099e+06  -0.039  0.96882    
NameLong-Term Care Insurance Credit                                                            1.246e+05  9.808e+05   0.127  0.89892    
NameLow-Income Housing Credit                                                                 -2.764e+04  1.113e+06  -0.025  0.98020    
NameMinimum Wage Reimbursement Credit                                                         -2.931e+05  1.006e+06  -0.291  0.77075    
NameMortgage Servicing Tax Credit                                                             -4.540e+05  1.085e+06  -0.418  0.67565    
NameNew York Youth Jobs Program Tax Credit                                                    -2.587e+05  9.381e+05  -0.276  0.78279    
NameQETC Capital Tax Credit                                                                    2.616e+05  1.386e+06   0.189  0.85032    
NameQETC Employment Credit                                                                     1.335e+05  1.026e+06   0.130  0.89641    
NameQETC Facilities, Operations, and Training Credit                                           5.153e+05  1.918e+06   0.269  0.78820    
NameReal Property Tax Relief Credit for Manufacturing                                         -2.635e+05  9.654e+05  -0.273  0.78490    
NameSpecial Additional Mortgage Recording Tax Credit                                           3.678e+04  9.244e+05   0.040  0.96827    
NameSTART-UP NY Tax Elimination Credit                                                         4.061e+03  1.130e+06   0.004  0.99713    
Group1,000,000 - 24,999,999                                                                    2.170e+05  3.501e+05   0.620  0.53548    
Group100,000 - 499,999                                                                         1.352e+05  3.579e+05   0.378  0.70572    
Group100,000,000 - 499,999,999                                                                 9.644e+05  3.937e+05   2.449  0.01441 *  
Group25,000,000 - 49,999,999                                                                   4.519e+05  4.223e+05   1.070  0.28474    
Group50,000,000 - 99,999,999                                                                   4.021e+05  4.235e+05   0.950  0.34247    
Group500,000 - 999,999                                                                         2.195e+05  3.880e+05   0.566  0.57170    
Group500,000,000 - and over                                                                    3.073e+06  3.846e+05   7.991 2.33e-15 ***
GroupZero or Net Loss                                                                          9.536e+05  3.339e+05   2.856  0.00433 ** 
Num                                                                                           -4.520e+02  8.569e+02  -0.527  0.59791    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3868000 on 1867 degrees of freedom
Multiple R-squared:  0.2361,    Adjusted R-squared:  0.2144 
F-statistic: 10.88 on 53 and 1867 DF,  p-value: < 2.2e-16

          GVIF Df GVIF^(1/(2*Df))
Year  2.125869  1        1.458036
Name  3.521453 43        1.014746
Group 1.510763  8        1.026124
Num   1.645484  1        1.282764

income.model <- lm(sat.formula, data = income_cleaned)

sat.model.summary(industry_cleaned, sat.field, sat.formula)

    Shapiro-Wilk normality test

data:  df[[field]]
W = 0.22287, p-value < 2.2e-16

[1] "kurtosis"
[1] 135.5482

Call:
lm(formula = sat.formula, data = df)

Residuals:
      Min        1Q    Median        3Q       Max 
-11581741   -371031    -23164    154182  28917959 

Coefficients:
                                                                                                Estimate Std. Error t value Pr(>|t|)    
(Intercept)                                                                                   -3.926e+07  2.051e+07  -1.914 0.055677 .  
Year                                                                                           1.936e+04  1.016e+04   1.905 0.056959 .  
NameAlternative Fuels and Electric Vehicle Recharging Property Credit                          5.584e+04  5.062e+05   0.110 0.912180    
NameAlternative Minimum Tax Credit                                                             3.523e+05  4.208e+05   0.837 0.402556    
NameBeer Production Credit                                                                     8.799e+04  6.261e+05   0.141 0.888249    
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 6/23/08 but before 7/1/15  1.919e+06  4.473e+05   4.290 1.86e-05 ***
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 7/1/15                     4.064e+06  7.278e+05   5.584 2.62e-08 ***
NameBrownfield Tax Credits - Redevelopment Tax Credit - Prior to 6/23/08                       1.054e+06  4.779e+05   2.206 0.027462 *  
NameBrownfield Tax Credits - Remediation Real Property Tax Credit                              1.327e+05  4.760e+05   0.279 0.780429    
NameClean Heating Fuel Credit                                                                  2.785e+05  4.595e+05   0.606 0.544549    
NameConservation Easement Tax Credit                                                           2.743e+04  4.700e+05   0.058 0.953457    
NameCredit for Employment of Persons with Disabilities                                         1.574e+05  5.069e+05   0.311 0.756142    
NameCredit for Purchase of an Automated External Defibrillator                                 1.082e+05  4.465e+05   0.242 0.808639    
NameCredit for Taxicabs & Livery Service Vehicles Accessible to Persons with Disabilities      2.090e+05  8.286e+05   0.252 0.800866    
NameEmpire State Apprentice Tax Credit                                                        -3.324e+05  1.012e+06  -0.329 0.742537    
NameEmpire State Commercial Production Credit                                                  3.524e+05  6.172e+05   0.571 0.568123    
NameEmpire State Film Post Production Credit                                                   5.332e+05  5.224e+05   1.021 0.307585    
NameEmpire State Film Production Credit                                                        1.170e+07  4.785e+05  24.458  < 2e-16 ***
NameEmpire State Musical and Theatrical Production Credit                                      7.676e+04  9.010e+05   0.085 0.932112    
NameExcelsior Jobs Program Credit                                                              7.086e+05  4.393e+05   1.613 0.106849    
NameEZ/QEZE Tax Credits - EZ Investment Tax Credit                                             1.381e+06  4.318e+05   3.199 0.001399 ** 
NameEZ/QEZE Tax Credits - EZ Wage Tax Credit                                                   3.715e+05  4.213e+05   0.882 0.377942    
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes                                  1.160e+06  4.192e+05   2.767 0.005700 ** 
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes For Corporate Partners           3.634e+05  4.311e+05   0.843 0.399359    
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit                                            2.567e+05  4.265e+05   0.602 0.547350    
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit For Corporate Partners                     7.379e+04  5.041e+05   0.146 0.883634    
NameFarm Workforce Retention Credit                                                            2.727e+04  5.352e+05   0.051 0.959361    
NameFarmers' School Tax Credit                                                                 1.287e+05  5.133e+05   0.251 0.802102    
NameHire a Veteran Credit                                                                      1.459e+05  8.253e+05   0.177 0.859709    
NameHistoric Properties Rehabilitation Credit                                                  1.875e+06  4.841e+05   3.874 0.000110 ***
NameInvestment Tax Credit                                                                      7.182e+05  4.129e+05   1.739 0.082075 .  
NameInvestment Tax Credit for the Financial Services Industry                                  6.339e+05  5.757e+05   1.101 0.270913    
NameLife Sciences Research & Development Tax Credit                                           -2.243e+03  9.007e+05  -0.002 0.998014    
NameLong-Term Care Insurance Credit                                                            1.385e+05  4.200e+05   0.330 0.741537    
NameLow-Income Housing Credit                                                                  1.642e+06  5.494e+05   2.988 0.002833 ** 
NameMinimum Wage Reimbursement Credit                                                          9.624e+04  4.381e+05   0.220 0.826159    
NameMortgage Servicing Tax Credit                                                              2.077e+05  6.462e+05   0.321 0.747934    
NameNew York Youth Jobs Program Tax Credit                                                     1.953e+05  4.273e+05   0.457 0.647604    
NameQETC Capital Tax Credit                                                                    2.986e+05  5.868e+05   0.509 0.610823    
NameQETC Employment Credit                                                                     8.982e+04  4.465e+05   0.201 0.840607    
NameQETC Facilities, Operations, and Training Credit                                           3.477e+05  6.711e+05   0.518 0.604441    
NameReal Property Tax Relief Credit for Manufacturing                                          1.520e+05  4.423e+05   0.344 0.731171    
NameSpecial Additional Mortgage Recording Tax Credit                                           2.609e+05  4.432e+05   0.589 0.556155    
NameSTART-UP NY Tax Elimination Credit                                                         1.703e+04  4.750e+05   0.036 0.971411    
GroupAdministrative and Support and Waste Management and Remediation Services                 -2.280e+03  2.519e+05  -0.009 0.992777    
GroupAdministrative/Support/Waste Management/Remediation Services                             -3.173e+03  2.798e+05  -0.011 0.990952    
GroupAgriculture, Forestry, Fishing and Hunting                                                7.269e+04  2.330e+05   0.312 0.755097    
GroupArts, Entertainment, and Recreation                                                       5.866e+05  2.317e+05   2.532 0.011408 *  
GroupConstruction                                                                             -1.699e+04  2.171e+05  -0.078 0.937621    
GroupEducational Services                                                                      5.569e+04  2.948e+05   0.189 0.850176    
GroupFinance and Insurance                                                                     2.139e+05  2.034e+05   1.051 0.293237    
GroupHealth Care and Social Assistance                                                         1.300e+04  2.290e+05   0.057 0.954731    
GroupInformation                                                                              -2.433e+05  2.178e+05  -1.117 0.263917    
GroupManagement of Companies and Enterprises                                                   3.355e+05  1.949e+05   1.721 0.085332 .  
GroupManufacturing                                                                             6.786e+05  2.028e+05   3.346 0.000831 ***
GroupMining                                                                                   -1.561e+04  3.593e+05  -0.043 0.965352    
GroupMining, Quarrying, and Oil and Gas Extraction                                             1.084e+05  3.011e+05   0.360 0.718901    
GroupOther Services (except Public Administration)                                            -6.462e+04  2.217e+05  -0.291 0.770697    
GroupProfessional, Scientific, and Technical Services                                          3.736e+05  2.085e+05   1.792 0.073214 .  
GroupReal Estate and Rental and Leasing                                                        9.506e+04  2.044e+05   0.465 0.641882    
GroupRetail Trade                                                                              4.746e+04  2.036e+05   0.233 0.815756    
GroupTransportation and Warehousing                                                           -1.866e+04  2.300e+05  -0.081 0.935321    
GroupUtilities                                                                                 5.308e+05  2.633e+05   2.016 0.043917 *  
GroupWholesale Trade                                                                           6.106e+04  2.081e+05   0.293 0.769261    
Num                                                                                           -9.657e+02  4.272e+02  -2.260 0.023889 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1612000 on 2411 degrees of freedom
Multiple R-squared:  0.4674,    Adjusted R-squared:  0.4533 
F-statistic: 33.06 on 64 and 2411 DF,  p-value: < 2.2e-16

          GVIF Df GVIF^(1/(2*Df))
Year  2.190806  1        1.480137
Name  5.185764 42        1.019787
Group 2.724217 20        1.025371
Num   1.370920  1        1.170863

industry.model <- lm(sat.formula, data = industry_cleaned)

Selecting Specific Diagnostic plots for linear models

plot(income.model, which = 1)

plot(income.model, which = 2)

plot(income.model, which = 3)

plot(income.model, which = 5)

Correcting violation of Normality in previous model with BoxCox transform

bc_func <- function (lm.cleaned, lambda.range){
  bc = boxCox(lm.cleaned, lambda = lambda.range)
  #Extracting the best lambda value.
  return(bc$x[which(bc$y == max(bc$y))])
}

#Income Group Dataset
income.lambda.bc = bc_func(income.model, seq(-0.2, 0.2, 1/10))

income.lambda.bc
[1] -0.01414141
#Industry Group Dataset
industry.lambda.bc = bc_func(industry.model, seq(-0.2, 0.2, 1/10))

industry.lambda.bc
[1] -0.03434343
bc_transform <- function(df, lambda.bc){
  return (df %>% 
            mutate(Avg.bc = (Avg^lambda.bc -1)/lambda.bc) %>% 
            select(-c(Avg))) #took out field Amount
}

#Income Group Dataset
income_cleaned_bc <- bc_transform(income_cleaned, income.lambda.bc)
income.model.bc = lm(Avg.bc ~ ., data = income_cleaned_bc)

#Industry Group Dataset
industry_cleaned_bc <- bc_transform(industry_cleaned, industry.lambda.bc)
industry.model.bc = lm(Avg.bc ~ ., data = industry_cleaned_bc)

Testing out appending a newly created dataframe to a list of dataframes with a Name for Shiny app

# income_cleaned_bc
# all.data <- list('income_cleaned' = income_cleaned, 'industry_cleaned' = industry_cleaned)
# all.data <- append(all.data, list('income_cleaned_bc' = income_cleaned_bc))
# all.data[['income_cleaned_bc']]

Testing out bc_func for migration to Shiny App global.R file

bc_funct <- function (df, lm.cleaned, lambda.range){
  bc = boxCox(lm.cleaned, lambda = lambda.range)
  lambda.bc = bc$x[which(bc$y == max(bc$y))]
  return(df %>% 
            mutate(Avg.bc = (Avg^lambda.bc -1)/lambda.bc) %>% 
            select(-c(Avg)))
}

bc_funct(income_cleaned, income.model, seq(-0.2, 0.2, 1/10))

Checking linear regression assumptions for the transformed data.

sat.formula.bc <- Avg.bc ~ .
sat.field.bc <- 'Avg.bc'

#Income
sat.model.summary(income_cleaned_bc, sat.field.bc, sat.formula.bc)

    Shapiro-Wilk normality test

data:  df[[field]]
W = 0.99696, p-value = 0.000782

[1] "kurtosis"
[1] -0.2553313

Call:
lm(formula = sat.formula, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.6597 -0.5738 -0.0113  0.5668  4.4826 

Coefficients:
                                                                                                Estimate Std. Error t value Pr(>|t|)    
(Intercept)                                                                                   -3.634e+01  1.456e+01  -2.496 0.012643 *  
Year                                                                                           2.288e-02  7.214e-03   3.171 0.001543 ** 
NameAlternative Fuels and Electric Vehicle Recharging Property Credit                         -8.643e-01  3.281e-01  -2.634 0.008510 ** 
NameAlternative Minimum Tax Credit                                                            -2.052e+00  2.577e-01  -7.962 2.91e-15 ***
NameBeer Production Credit                                                                     5.687e-01  3.407e-01   1.669 0.095234 .  
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 6/23/08 but before 7/1/15  1.715e+00  2.630e-01   6.521 8.99e-11 ***
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 7/1/15                     2.676e+00  3.754e-01   7.130 1.43e-12 ***
NameBrownfield Tax Credits - Redevelopment Tax Credit - Prior to 6/23/08                       1.331e+00  2.622e-01   5.076 4.24e-07 ***
NameBrownfield Tax Credits - Remediation Real Property Tax Credit                              5.458e-02  2.620e-01   0.208 0.834991    
NameClean Heating Fuel Credit                                                                 -3.086e+00  2.705e-01 -11.409  < 2e-16 ***
NameConservation Easement Tax Credit                                                          -2.137e+00  2.810e-01  -7.606 4.45e-14 ***
NameCredit for Employment of Persons with Disabilities                                        -3.118e+00  2.956e-01 -10.547  < 2e-16 ***
NameCredit for Purchase of an Automated External Defibrillator                                -2.938e+00  2.560e-01 -11.473  < 2e-16 ***
NameCredit for Taxicabs & Livery Service Vehicles Accessible to Persons with Disabilities     -5.673e-01  4.698e-01  -1.207 0.227430    
NameEmpire State Apprentice Tax Credit                                                        -2.207e+00  4.024e-01  -5.485 4.71e-08 ***
NameEmpire State Commercial Production Credit                                                  6.075e-02  3.410e-01   0.178 0.858634    
NameEmpire State Film Post Production Credit                                                   1.101e+00  2.769e-01   3.977 7.25e-05 ***
NameEmpire State Film Production Credit                                                        2.853e+00  2.632e-01  10.838  < 2e-16 ***
NameEmpire State Musical and Theatrical Production Credit                                      2.508e-01  4.688e-01   0.535 0.592803    
NameExcelsior Jobs Program Credit                                                              4.651e-01  2.521e-01   1.845 0.065178 .  
NameEZ/QEZE Tax Credits - EZ Investment Tax Credit                                             8.876e-01  2.341e-01   3.792 0.000154 ***
NameEZ/QEZE Tax Credits - EZ Wage Tax Credit                                                   1.775e-01  2.433e-01   0.730 0.465701    
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes                                  1.220e+00  2.440e-01   5.000 6.26e-07 ***
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes For Corporate Partners           1.182e-01  2.522e-01   0.469 0.639260    
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit                                           -8.497e-01  2.479e-01  -3.427 0.000623 ***
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit For Corporate Partners                    -1.358e+00  2.756e-01  -4.928 9.02e-07 ***
NameFarm Workforce Retention Credit                                                           -1.612e+00  3.394e-01  -4.749 2.20e-06 ***
NameFarmers' School Tax Credit                                                                -1.311e+00  2.696e-01  -4.863 1.26e-06 ***
NameHire a Veteran Credit                                                                     -2.915e+00  4.706e-01  -6.195 7.15e-10 ***
NameHistoric Properties Rehabilitation Credit                                                  1.918e+00  2.786e-01   6.886 7.81e-12 ***
NameIndustrial or Manufacturing Business Tax Credit                                           -1.718e+00  2.836e-01  -6.059 1.66e-09 ***
NameInvestment Tax Credit                                                                      7.147e-02  2.349e-01   0.304 0.760985    
NameInvestment Tax Credit for the Financial Services Industry                                  3.176e-01  2.662e-01   1.193 0.232870    
NameLife Sciences Research & Development Tax Credit                                            7.033e-01  5.543e-01   1.269 0.204728    
NameLong-Term Care Insurance Credit                                                           -2.863e+00  2.590e-01 -11.051  < 2e-16 ***
NameLow-Income Housing Credit                                                                 -9.063e-01  2.940e-01  -3.083 0.002080 ** 
NameMinimum Wage Reimbursement Credit                                                         -1.241e+00  2.656e-01  -4.674 3.17e-06 ***
NameMortgage Servicing Tax Credit                                                             -9.378e-01  2.865e-01  -3.273 0.001084 ** 
NameNew York Youth Jobs Program Tax Credit                                                    -1.330e+00  2.478e-01  -5.367 9.01e-08 ***
NameQETC Capital Tax Credit                                                                    4.561e-01  3.661e-01   1.246 0.212956    
NameQETC Employment Credit                                                                    -5.888e-01  2.709e-01  -2.174 0.029855 *  
NameQETC Facilities, Operations, and Training Credit                                           5.799e-01  5.065e-01   1.145 0.252462    
NameReal Property Tax Relief Credit for Manufacturing                                         -1.518e+00  2.550e-01  -5.956 3.09e-09 ***
NameSpecial Additional Mortgage Recording Tax Credit                                          -2.309e-01  2.441e-01  -0.946 0.344374    
NameSTART-UP NY Tax Elimination Credit                                                        -2.193e+00  2.985e-01  -7.345 3.05e-13 ***
Group1,000,000 - 24,999,999                                                                    1.090e+00  9.246e-02  11.785  < 2e-16 ***
Group100,000 - 499,999                                                                         3.590e-01  9.451e-02   3.798 0.000150 ***
Group100,000,000 - 499,999,999                                                                 1.685e+00  1.040e-01  16.202  < 2e-16 ***
Group25,000,000 - 49,999,999                                                                   1.325e+00  1.115e-01  11.883  < 2e-16 ***
Group50,000,000 - 99,999,999                                                                   1.473e+00  1.118e-01  13.172  < 2e-16 ***
Group500,000 - 999,999                                                                         6.032e-01  1.025e-01   5.886 4.67e-09 ***
Group500,000,000 - and over                                                                    2.332e+00  1.016e-01  22.953  < 2e-16 ***
GroupZero or Net Loss                                                                          9.934e-01  8.817e-02  11.267  < 2e-16 ***
Num                                                                                           -1.533e-03  2.263e-04  -6.775 1.66e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.022 on 1867 degrees of freedom
Multiple R-squared:  0.7368,    Adjusted R-squared:  0.7293 
F-statistic: 98.61 on 53 and 1867 DF,  p-value: < 2.2e-16

          GVIF Df GVIF^(1/(2*Df))
Year  2.125869  1        1.458036
Name  3.521453 43        1.014746
Group 1.510763  8        1.026124
Num   1.645484  1        1.282764

#Industry
sat.model.summary(industry_cleaned_bc, sat.field.bc, sat.formula.bc)

    Shapiro-Wilk normality test

data:  df[[field]]
W = 0.9902, p-value = 5.826e-12

[1] "kurtosis"
[1] -0.4869026

Call:
lm(formula = sat.formula, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.2888 -0.4697  0.0183  0.4928  3.9068 

Coefficients:
                                                                                                Estimate Std. Error t value Pr(>|t|)    
(Intercept)                                                                                   -6.095e+01  1.107e+01  -5.505 4.09e-08 ***
Year                                                                                           3.440e-02  5.488e-03   6.269 4.30e-10 ***
NameAlternative Fuels and Electric Vehicle Recharging Property Credit                          2.665e-01  2.733e-01   0.975 0.329737    
NameAlternative Minimum Tax Credit                                                            -2.463e+00  2.272e-01 -10.839  < 2e-16 ***
NameBeer Production Credit                                                                     6.334e-01  3.381e-01   1.873 0.061126 .  
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 6/23/08 but before 7/1/15  2.198e+00  2.415e-01   9.100  < 2e-16 ***
NameBrownfield Tax Credits - Redevelopment Tax Credit - On or after 7/1/15                     2.727e+00  3.930e-01   6.939 5.06e-12 ***
NameBrownfield Tax Credits - Redevelopment Tax Credit - Prior to 6/23/08                       1.586e+00  2.581e-01   6.148 9.17e-10 ***
NameBrownfield Tax Credits - Remediation Real Property Tax Credit                              9.695e-01  2.570e-01   3.772 0.000166 ***
NameClean Heating Fuel Credit                                                                 -2.544e+00  2.481e-01 -10.252  < 2e-16 ***
NameConservation Easement Tax Credit                                                          -1.123e+00  2.538e-01  -4.423 1.02e-05 ***
NameCredit for Employment of Persons with Disabilities                                        -1.245e+00  2.737e-01  -4.549 5.67e-06 ***
NameCredit for Purchase of an Automated External Defibrillator                                -1.535e+00  2.411e-01  -6.368 2.29e-10 ***
NameCredit for Taxicabs & Livery Service Vehicles Accessible to Persons with Disabilities     -8.171e-02  4.474e-01  -0.183 0.855119    
NameEmpire State Apprentice Tax Credit                                                        -8.683e-01  5.464e-01  -1.589 0.112125    
NameEmpire State Commercial Production Credit                                                  6.235e-01  3.333e-01   1.871 0.061481 .  
NameEmpire State Film Post Production Credit                                                   1.439e+00  2.821e-01   5.100 3.66e-07 ***
NameEmpire State Film Production Credit                                                        3.232e+00  2.584e-01  12.509  < 2e-16 ***
NameEmpire State Musical and Theatrical Production Credit                                      1.012e+00  4.865e-01   2.080 0.037608 *  
NameExcelsior Jobs Program Credit                                                              1.643e+00  2.372e-01   6.929 5.42e-12 ***
NameEZ/QEZE Tax Credits - EZ Investment Tax Credit                                             1.310e+00  2.332e-01   5.617 2.17e-08 ***
NameEZ/QEZE Tax Credits - EZ Wage Tax Credit                                                   7.127e-01  2.275e-01   3.133 0.001750 ** 
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes                                  1.707e+00  2.264e-01   7.540 6.61e-14 ***
NameEZ/QEZE Tax Credits - QEZE Credit for Real Property Taxes For Corporate Partners           9.777e-01  2.328e-01   4.200 2.77e-05 ***
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit                                            1.609e-01  2.303e-01   0.699 0.484921    
NameEZ/QEZE Tax Credits - QEZE Tax Reduction Credit For Corporate Partners                    -5.241e-01  2.722e-01  -1.925 0.054320 .  
NameFarm Workforce Retention Credit                                                           -8.623e-01  2.890e-01  -2.984 0.002876 ** 
NameFarmers' School Tax Credit                                                                -1.158e+00  2.771e-01  -4.179 3.03e-05 ***
NameHire a Veteran Credit                                                                     -1.040e+00  4.456e-01  -2.335 0.019638 *  
NameHistoric Properties Rehabilitation Credit                                                  2.397e+00  2.614e-01   9.172  < 2e-16 ***
NameInvestment Tax Credit                                                                      6.981e-01  2.230e-01   3.131 0.001763 ** 
NameInvestment Tax Credit for the Financial Services Industry                                  1.560e+00  3.108e-01   5.019 5.59e-07 ***
NameLife Sciences Research & Development Tax Credit                                            9.057e-01  4.864e-01   1.862 0.062697 .  
NameLong-Term Care Insurance Credit                                                           -1.867e+00  2.268e-01  -8.231 3.01e-16 ***
NameLow-Income Housing Credit                                                                  1.331e+00  2.967e-01   4.487 7.57e-06 ***
NameMinimum Wage Reimbursement Credit                                                         -9.161e-01  2.366e-01  -3.872 0.000111 ***
NameMortgage Servicing Tax Credit                                                              8.932e-01  3.489e-01   2.560 0.010534 *  
NameNew York Youth Jobs Program Tax Credit                                                     1.263e-01  2.307e-01   0.548 0.584069    
NameQETC Capital Tax Credit                                                                    1.162e+00  3.168e-01   3.667 0.000251 ***
NameQETC Employment Credit                                                                    -3.048e-01  2.411e-01  -1.264 0.206249    
NameQETC Facilities, Operations, and Training Credit                                           1.147e+00  3.624e-01   3.165 0.001571 ** 
NameReal Property Tax Relief Credit for Manufacturing                                         -6.559e-01  2.388e-01  -2.746 0.006077 ** 
NameSpecial Additional Mortgage Recording Tax Credit                                           7.505e-01  2.393e-01   3.136 0.001736 ** 
NameSTART-UP NY Tax Elimination Credit                                                        -1.834e+00  2.565e-01  -7.151 1.14e-12 ***
GroupAdministrative and Support and Waste Management and Remediation Services                  2.878e-01  1.360e-01   2.116 0.034417 *  
GroupAdministrative/Support/Waste Management/Remediation Services                              1.675e-01  1.511e-01   1.109 0.267612    
GroupAgriculture, Forestry, Fishing and Hunting                                               -1.132e-01  1.258e-01  -0.899 0.368486    
GroupArts, Entertainment, and Recreation                                                       5.595e-01  1.251e-01   4.473 8.09e-06 ***
GroupConstruction                                                                             -4.299e-02  1.172e-01  -0.367 0.713860    
GroupEducational Services                                                                      2.253e-01  1.592e-01   1.415 0.157160    
GroupFinance and Insurance                                                                     5.350e-01  1.099e-01   4.870 1.19e-06 ***
GroupHealth Care and Social Assistance                                                        -6.777e-02  1.237e-01  -0.548 0.583720    
GroupInformation                                                                               7.098e-01  1.176e-01   6.037 1.81e-09 ***
GroupManagement of Companies and Enterprises                                                   6.672e-01  1.052e-01   6.340 2.73e-10 ***
GroupManufacturing                                                                             4.608e-01  1.095e-01   4.208 2.67e-05 ***
GroupMining                                                                                    2.515e-01  1.940e-01   1.296 0.194977    
GroupMining, Quarrying, and Oil and Gas Extraction                                             3.869e-01  1.626e-01   2.379 0.017421 *  
GroupOther Services (except Public Administration)                                            -1.550e-01  1.197e-01  -1.295 0.195482    
GroupProfessional, Scientific, and Technical Services                                          4.875e-01  1.126e-01   4.331 1.55e-05 ***
GroupReal Estate and Rental and Leasing                                                        1.461e-01  1.104e-01   1.324 0.185596    
GroupRetail Trade                                                                              3.754e-01  1.100e-01   3.414 0.000650 ***
GroupTransportation and Warehousing                                                            2.125e-01  1.242e-01   1.711 0.087179 .  
GroupUtilities                                                                                 6.972e-01  1.422e-01   4.904 1.00e-06 ***
GroupWholesale Trade                                                                           4.367e-01  1.124e-01   3.886 0.000105 ***
Num                                                                                            4.542e-04  2.307e-04   1.969 0.049082 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8703 on 2411 degrees of freedom
Multiple R-squared:  0.7631,    Adjusted R-squared:  0.7569 
F-statistic: 121.4 on 64 and 2411 DF,  p-value: < 2.2e-16

          GVIF Df GVIF^(1/(2*Df))
Year  2.190806  1        1.480137
Name  5.185764 42        1.019787
Group 2.724217 20        1.025371
Num   1.370920  1        1.170863

avPlots(income.model.bc)

NA

NA

NA

NA
NA

BIC comparison before and after BoxCox transform

BIC(income.model.bc, income.model)
BIC(industry.model.bc, industry.model)

Stepwise Regression on Income_cat_bc (boxcox transformed dataset)

#creating dummy variable columns for stepwise
dummy_func <- function (df){
  x = model.matrix(Avg.bc ~., df)[, -1]
  dummy_bc = as.data.frame(x) %>% mutate(Avg.bc = df$Avg.bc)
  #colnames(dummy_bc) <- str_replace_all(colnames(dummy_bc), "-|'|/| |,|�|&" , '_')
  colnames(dummy_bc) <- str_replace_all(colnames(dummy_bc), "[-'/ ,�&()`]" , '_')
  return(dummy_bc)
}

Cleaning column names further so stepwise regression doesn’t present any errors

#Income Group Dataset
income.dummy.bc <- dummy_func(income_cleaned_bc)
#colnames(income.dummy.bc)[37] <- 'NameManufactureru0092s_Real_Property_Tax_Credit'
colnames(income.dummy.bc)

#Industry Group Dataset
industry.dummy.bc <- dummy_func(industry_cleaned_bc)
#colnames(industry.dummy.bc)[35] <- 'NameManufactureru0092s_Real_Property_Tax_Credit'
colnames(industry.dummy.bc)

Stepwise regression using BIC as the criteria (k = log(n)).

#Creating Stepwise Models
bcs = list(income = income.dummy.bc, industry = industry.dummy.bc)
model.fulls = list(income = lm(Avg.bc ~ ., data = income.dummy.bc), industry = lm(Avg.bc ~ ., data = industry.dummy.bc)) #All variables
model.emptys = list(income = lm(Avg.bc ~ 1, data = income.dummy.bc), industry = lm(Avg.bc ~ 1, data = industry.dummy.bc)) #intercept only
k = c('income', 'industry')
forwardBIC = list(income = NULL, industry = NULL)
backwardBIC = list(income = NULL, industry = NULL)

for (i in k){
  bc = bcs[[i]]
  scope = list(lower = formula(model.emptys[[i]]), upper = formula(model.fulls[[i]]))
  n_obs = bc %>% count() %>% dplyr::first()
  forwardBIC[[i]] = step(model.emptys[[i]], scope, direction = "forward", k = log(n_obs))
  backwardBIC[[i]] = step(model.fulls[[i]], scope, direction = "backward", k = log(n_obs))
}

Selecting Best Formula per Dataset from Stepwise Regressions

bic_func(forwardBIC[['income']])
[1] "Adjusted R Squared:"
Error in summary(BIC.model) : object 'forwardBIC' not found

Best Model Selection from Stepwise

#The Best Models selected for both income and industry were forwardBIC.

#Income Group Dataset
income.best.formula <- forwardBIC[['income']]$call[[2]]
income.best.formula

#Industry Group Dataset
industry.best.formula <- forwardBIC[['industry']]$call[[2]]
industry.best.formula

Splitting data up into test data and training data (test data is for year 2019, training is the rest)

test_train_split <- function(dummy_bc, best.formula) {
  # data.test <- dummy_bc %>% filter(Year == 2019)
  # data.train <- dummy_bc %>% filter(Year != 2019)
  X <- model.matrix(best.formula, data = dummy_bc)[,-1]
  y <- as.matrix(dummy_bc %>% select(all.vars(best.formula)[1]))
  
  set.seed(0)
  train.i = sample(1:nrow(dummy_bc), 0.8*nrow(dummy_bc), replace = F)
  
  #train
  X.train <- X[train.i,]
  y.train <- y[train.i,]
  
  #test
  X.test <- X[-train.i,]
  y.test <- y[-train.i,]
  
  data.train <- as.data.frame(cbind(y.train, X.train))
  data.test <- as.data.frame(cbind(y.test, X.test))
  colnames(data.train)[1] = all.vars(best.formula)[1]
  colnames(data.test)[1] = all.vars(best.formula)[1]
  
  return (list('X.train' = X.train, 'y.train' = y.train, 'X.test' = X.test, 'y.test' = y.test, 'data.train' = data.train, 'data.test' = data.test))
}
test_train_split_old <- function(dummy_bc, best.formula) {
  # data.test <- dummy_bc %>% filter(Year == 2019)
  # data.train <- dummy_bc %>% filter(Year != 2019)
  set.seed(0)
  train.i = sample(1:nrow(dummy_bc), 0.8*nrow(dummy_bc), replace = F)
  data.train <- dummy_bc %>% slice(train.i)
  data.test <- dummy_bc %>% slice(-train.i)
  
  #train
  #X.train <- as.matrix(data.train %>% select(-Avg.bc))
  X.train <- model.matrix(best.formula, data = data.train)[,-1]
  y.train <- as.matrix(data.train %>% select(all.vars(best.formula)[1]))

  #test
  #X.test <- as.matrix(data.test %>% select(-Avg.bc))
  X.test <- model.matrix(best.formula, data = data.test)[,-1]
  y.test <- as.matrix(data.test %>% select(all.vars(best.formula)[1]))
  
  #return (list('X.train' = X.train, 'y.train' = y.train, 'X.test' = X.test, 'y.test' = y.test, 'data.train' = data.train, 'data.test' = data.test))
}

#Income
income.data.split.sat <- test_train_split(income.dummy.bc, Avg.bc ~ .)
income.data.split <- test_train_split(income.dummy.bc, income.best.formula)

#Industry
industry.data.split.sat <- test_train_split(industry.dummy.bc, Avg.bc ~ .)
industry.data.split <- test_train_split(industry.dummy.bc, industry.best.formula)

test_train_split(income_cleaned, sat.formula)

Lasso regression for comparison to Forward Stepwise

# calc_MSE <- function (model, x.test, y.test){
#   y.predict <- predict(model, newdata = x.test)
#   return(mean((y.predict - y.test)^2))
# }

# xy.splits <- list('income' = income.data.split, 
#                   'industry' = industry.data.split, 
#                   'income.sat' = income.data.split.sat, 
#                   'industry.sat' = industry.data.split.sat)
# 
# lasso.list <- c('income', 'industry', 'income.sat', 'industry.sat')
# baseline.list <- c('income.sat', 'industry.sat', 'income.sat', 'industry.sat')
# ridge.alpha <- 0
# 
# for (a in 1:4){
#   i = lasso.list[a]
#   b = baseline.list[a]
#   X.train <- xy.splits[[i]][['X.train']]
#   y.train <- xy.splits[[i]][['y.train']]
#   X.test <- xy.splits[[i]][['X.test']]
#   y.test <- xy.splits[[i]][['y.test']]
#   X.test.sat <- xy.splits[[b]][['X.test']]
#   y.test.sat <- xy.splits[[b]][['y.test']]
#   data.train <- xy.splits[[i]][['data.train']]
#   data.test <- xy.splits[[i]][['data.test']]
#   
#   #create lambda grid
#   lambda.grid = 10^seq(2, -5, length = 100)
#   
#   #create lasso models with lambda.grid
#   lasso.models = glmnet(X.train, y.train, alpha = ridge.alpha, lambda = lambda.grid)
#   
#   #visualize coefficient shrinkage
#   plot(lasso.models, xvar = "lambda", label = TRUE, main = paste("Lasso Regression:", i))
#   
#   #Cross Validation to find best lambda
#   set.seed(0)
#   cv.lasso.models <- cv.glmnet(X.train, y.train, alpha = ridge.alpha, lambda = lambda.grid, nfolds = 10)
#   
#   #visualize cross validation for lambda that minimizes the mean squared error.
#   plot(cv.lasso.models, main = paste("Lasso Regression:", i))
#   
#   #Checking the best lambda
#   log(cv.lasso.models$lambda.min)
#   best.lambda <- cv.lasso.models$lambda.min
#   print(paste(i, ' best.lambda:', best.lambda))
#   # best lambda with all the variables was found to be 0.0006892612
#   # best lambda with only the bwdBIC coefficients included was found to be 0.0003053856
#   
#   #looking at the lasso coefficients for the best.lambda
#   best.lambda.coeff <- predict(lasso.models, s = best.lambda, type = "coefficients")
#   print('Number of Coefficients:')
#   print(dim(best.lambda.coeff)[1])
#   
#   #fitting a model with the best lambda found to be 0.000689 and using it to make predictions for the testing data.
#   lasso.best.lambda.train.pred <- predict(lasso.models, s = best.lambda, newx = X.test)
#   lasso.best.lambda.train.pred
#   
#   #checking MSE
#   MSE.lasso <- mean((lasso.best.lambda.train.pred - y.test)^2)
#   sat.model.bc <- lm(Avg.bc ~., data = data.train)
#   
#   
#   temp.df <- as.data.frame(X.test.sat) #temp fix
#   colnames(temp.df) <- str_replace_all(colnames(temp.df), "[`]", '')
#   
#   y.predict <- predict(sat.model.bc, newdata = temp.df)
#   MSE.sat <- mean((y.predict - y.test.sat)^2)
#   
#   print(paste(i, ' Lasso MSE: ', MSE.lasso, ' ', b, ' Saturated MSE: ', MSE.sat))
# 
#   metrics <- eval_results(y.test, lasso.best.lambda.train.pred, data.test)
#   print(metrics)
#   print('********************************')
# }

Function to show metrics (R^2 and MSE) for Regularization (Ridge/Lasso)

regularization_func <- function (data, alpha, name){
  X.train <- data[['X.train']]
  y.train <- data[['y.train']]
  X.test <- data [['X.test']]
  y.test <- data[['y.test']]
  data.test <- data[['data.test']]
  # print(colnames(X.train))
  # print(colnames(X.test))
  # print(setdiff(colnames(X.train), colnames(X.test)))
  
  #create lambda grid
  lambda.grid = 10^seq(10, -10, length = 100)
  
  #create lasso models with lambda.grid
  lasso.models = glmnet(X.train, y.train, alpha = alpha, lambda = lambda.grid)
  
  #visualize coefficient shrinkage
  # plot(lasso.models, xvar = "lambda", label = TRUE, main = paste("Lasso Regression:", i))
  
  #Cross Validation to find best lambda
  set.seed(0)
  cv.lasso.models <- cv.glmnet(X.train, y.train, alpha = alpha, lambda = lambda.grid, nfolds = 10)
  
  #visualize cross validation for lambda that minimizes the mean squared error.
  plot(cv.lasso.models, main = paste("Alpha:", alpha, "Regression:", name))
  
  #Checking the best lambda
  # log(cv.lasso.models$lambda.min)
  # best.lambda <- cv.lasso.models$lambda.min
  # print(paste(i, ' best.lambda:', best.lambda))
  # best lambda with all the variables was found to be 0.0006892612
  # best lambda with only the bwdBIC coefficients included was found to be 0.0003053856
  
  #looking at the lasso coefficients for the best.lambda
  # best.lambda.coeff <- predict(lasso.models, s = cv.lasso.models$lambda.min, type = "coefficients")
  # print('Number of Coefficients:')
  # print(dim(best.lambda.coeff)[1])
  
  #fitting a model with the best lambda found to be 0.000689 and using it to make predictions for the testing data.
  lasso.best.lambda.train.pred <- predict(lasso.models, s = cv.lasso.models$lambda.min, newx = X.test)
  lasso.best.lambda.train.pred
  
  #checking MSE
  MSE.lasso <- mean((lasso.best.lambda.train.pred - y.test)^2)
  print(paste('Dimensions of the Alpha:', alpha, ' Regression Coefficients for:', name))
  print(dim(coef(lasso.models))[1])
  p = dim(coef(lasso.models))[1]
  return(eval_results(y.test, lasso.best.lambda.train.pred, data.test, p)['Rsquare'])
}
regularization_func(all.splits[['income_cleaned']], 0, 'income_cleaned')
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income_cleaned"
[1] 54
    Rsquare 
-0.01019062 

regularization_func(all.splits[['income_cleaned_bc']], 0, 'income_cleaned_bc')
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income_cleaned_bc"
[1] 54
  Rsquare 
0.6750177 

regularization_func(all.splits[['income.data.split.sat']], 0, 'income.data.split.sat')
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income.data.split.sat"
[1] 54
  Rsquare 
0.6750177 

#all.dfs <- list(income_cleaned, income_cleaned_bc, income.dummy.bc)

formulas <- list(income_cleaned = sat.formula, 
                 income_cleaned_bc = sat.formula.bc, 
                 income.data.split.sat = sat.formula.bc, 
                 income.data.split.best = income.best.formula,
                 industry_cleaned = sat.formula, 
                 industry_cleaned_bc = sat.formula.bc, 
                 industry.data.split.sat = sat.formula.bc, 
                 industry.data.split.best = industry.best.formula)

all.splits <- list(
  'income_cleaned' = test_train_split(income_cleaned, formulas[['income_cleaned']]),
  'income_cleaned_bc' = test_train_split(income_cleaned_bc, formulas[['income_cleaned_bc']]),
  'income.data.split.sat' = test_train_split(income.dummy.bc, formulas[['income.data.split.sat']]),
  'income.data.split.best' = test_train_split(income.dummy.bc, formulas[['income.data.split.best']]),
  'industry_cleaned' = test_train_split(industry_cleaned, formulas[['industry_cleaned']]),
  'industry_cleaned_bc' = test_train_split(industry_cleaned_bc, formulas[['industry_cleaned_bc']]),
  'industry.data.split.sat' = test_train_split(industry.dummy.bc, formulas[['industry.data.split.sat']]),
  'industry.data.split.best' = test_train_split(industry.dummy.bc, formulas[['industry.data.split.best']])
)

#For loops initialization
no.reg.r2 <- c() 
lasso.reg.r2 <- c()
ridge.reg.r2 <- c()


for (i in names(all.splits)) {
  #no regularization
  m = lm(formulas[[i]], all.splits[[i]][['data.train']])
  #no.reg.r2 <- c(no.reg.r2, summary(m)$adj.r.squared)
  y.predict = predict(m, newdata = as.data.frame(all.splits[[i]][['X.test']]))
  adj.R2 <- eval_results(all.splits[[i]][['y.test']], y.predict, all.splits[[i]][['data.test']], length(coef(m)))['Rsquare']
  no.reg.r2 <- c(no.reg.r2, adj.R2)
  
  #lasso regularization
  lasso.reg.r2 <- c(lasso.reg.r2, regularization_func(all.splits[[i]], 1, i))
  
  #ridge regularization
  ridge.reg.r2 <- c(ridge.reg.r2, regularization_func(all.splits[[i]], 0, i))
}
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: income_cleaned"
[1] 54

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income_cleaned"
[1] 54
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: income_cleaned_bc"
[1] 54
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income_cleaned_bc"
[1] 54
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: income.data.split.sat"
[1] 54
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income.data.split.sat"
[1] 54
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: income.data.split.best"
[1] 41
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: income.data.split.best"
[1] 41
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: industry_cleaned"
[1] 65
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: industry_cleaned"
[1] 65
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: industry_cleaned_bc"
[1] 65
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: industry_cleaned_bc"
[1] 65
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: industry.data.split.sat"
[1] 65
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: industry.data.split.sat"
[1] 65
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 1  Regression Coefficients for: industry.data.split.best"
[1] 42
Warning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' valuesWarning: collapsing to unique 'x' values

Warning: collapsing to unique 'x' values
[1] "Dimensions of the Alpha: 0  Regression Coefficients for: industry.data.split.best"
[1] 42

df.rsquare <- as.data.frame(cbind('noReg' = no.reg.r2, 'lassoReg' = lasso.reg.r2, 'ridgeReg' = ridge.reg.r2))
rownames(df.rsquare) = names(all.splits)
df.rsquare
# sat.model.bc <- lm(Avg.bc ~., data = xy.splits.sat[['industry']][['data.train']])
# 
# temp.df <- as.data.frame(xy.splits.sat[['industry']][['X.test']])
# 
# colnames(temp.df)[57]
# 
# colnames(temp.df) <- str_replace_all(colnames(temp.df), "[`]", '')
# colnames(temp.df)
# 
# y.predict <- predict(sat.model.bc, newdata = temp.df)
# MSE.sat <- mean((y.predict - xy.splits.sat[['industry']][['y.test']])^2)
# 
# print(paste(i, ' Lasso MSE: ', MSE.lasso, ' Saturated MSE: ', MSE.sat))
# 
# summary(sat.model.bc)$coefficients
# as.data.frame(xy.splits.sat[['industry']][['X.test']]) %>% select(starts_with('`GroupOth'))
# Calculate R squared from true values and predictions
eval_results <- function(true, predicted, df, p) {
  n = nrow(df)
  adj.RSS <- sum((predicted - true)^2)/(n-p-1)
  adj.TSS <- sum((true - mean(true))^2)/(n-1)
  adj.R_square <- 1 - adj.RSS / adj.TSS
  #RMSE = sqrt(RSS/n)
  
  return(c(Rsquare = adj.R_square))
}

#formula for adjusted R^2 found in following link.
#https://www.graphpad.com/guides/prism/latest/curve-fitting/reg_adjusted-r-squared.htm

Additional Calculations

as.data.frame(lasso.best.lambda.train.pred) %>% mutate(Avg_in_dollars = (lasso.best.lambda.train.pred*lambda.bc+1)^(1/lambda.bc))
income.sat.data.split <- test_train_split(income.dummy.bc, Avg.bc ~ .)
income.sat.data.split[['X.train']]

sat.model.bc <- lm(Avg.bc ~., data = as.data.frame(cbind(income.sat.data.split[['X.train']], income.sat.data.split[['y.train']])))
summary(sat.model.bc)

calc_MSE(sat.model.bc, as.data.frame(income.sat.data.split[['X.test']]), income.sat.data.split[['y.test']])


sat.y.predict <- predict(sat.model.bc, newdata = as.data.frame(income.sat.data.split[['X.test']]))
mean((sat.y.predict - income.sat.data.split[['y.test']])^2)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpDYWxsIExpYnJhcmllcwpgYGB7cn0gCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNhcikKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KGdsbW5ldCkKYGBgCgoKQ2FsbGluZyB0aGUgVHJhbnNmb3JtZWQgRGF0YXNldHMKYGBge3J9CmluY29tZV9jbGVhbmVkID0gcmVhZF9jc3YoJ1NoaW55X2FwcC9kYXRhL2luY29tZV9jbGVhbmVkLmNzdicpCmluZHVzdHJ5X2NsZWFuZWQgPSByZWFkX2NzdignU2hpbnlfYXBwL2RhdGEvaW5kdXN0cnlfY2xlYW5lZC5jc3YnKQpgYGAKCgpDcmVhdGluZyB0aGUgTW9kZWxzCmBgYHtyfQpzYXQubW9kZWwuc3VtbWFyeSA8LSBmdW5jdGlvbiAoZGYsIGZpZWxkLCBzYXQuZm9ybXVsYSl7CiAgICAKICAgICNTaGFwaXJvLVdpbGtzIHRlc3QgdG8gZXZhbHVhdGUgbm9ybWFsaXR5CiAgICBwcmludChzaGFwaXJvLnRlc3QoZGZbW2ZpZWxkXV0pKQogICAgCiAgICAjS3VydG9zaXMgZXZhbHVhdGlvbiAobm9ybWFsIGRpc3RyaWJ1dGlvbiBoYXMgYSB2YWx1ZSBjbG9zZSB0byAzKQogICAgcHJpbnQoJ2t1cnRvc2lzJykKICAgIHByaW50KGt1cnRvc2lzKGRmW1tmaWVsZF1dKSkKICAgIGxpbmVhci5tb2RlbC5jbGVhbmVkID0gbG0oc2F0LmZvcm11bGEsIGRhdGEgPSBkZikKICAgIHByaW50KHN1bW1hcnkobGluZWFyLm1vZGVsLmNsZWFuZWQpKQogICAgcGxvdChsaW5lYXIubW9kZWwuY2xlYW5lZCkKICAgIAogICAgI2hpc3RvZ3JhbXMgb2YgcmVzcG9uc2UgdmFyaWFibGUgdG8gY2hlY2sgZGlzdHJpYnV0aW9uCiAgICBwcmludChkZiAlPiUgCiAgICAgIGdncGxvdChhZXNfc3RyaW5nKGZpZWxkKSkgKyAKICAgICAgZ2VvbV9oaXN0b2dyYW0oKSArIAogICAgICBsYWJzKHRpdGxlID0gJ0F2ZXJhZ2UgQ3JlZGl0IEFtb3VudCBEaXN0cmlidXRpb24nKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkpCiAgICAKICAgICNDaGVja2luZyBtdWx0aWNvbGxpbmVhcml0eSB1c2luZyBWSUYgbWVhc3VyZW1lbnQKICAgIHByaW50KHZpZihsaW5lYXIubW9kZWwuY2xlYW5lZCkpCiAgICBpbmZsdWVuY2VQbG90KGxpbmVhci5tb2RlbC5jbGVhbmVkKQogICAgI2F2UGxvdHMobGluZWFyLm1vZGVsLmNsZWFuZWQpCn0KCgpzYXQuZm9ybXVsYSA8LSBBdmcgfiAuCnNhdC5maWVsZCA8LSAnQXZnJwoKc2F0Lm1vZGVsLnN1bW1hcnkoaW5jb21lX2NsZWFuZWQsIHNhdC5maWVsZCwgc2F0LmZvcm11bGEpCmluY29tZS5tb2RlbCA8LSBsbShzYXQuZm9ybXVsYSwgZGF0YSA9IGluY29tZV9jbGVhbmVkKQoKc2F0Lm1vZGVsLnN1bW1hcnkoaW5kdXN0cnlfY2xlYW5lZCwgc2F0LmZpZWxkLCBzYXQuZm9ybXVsYSkKaW5kdXN0cnkubW9kZWwgPC0gbG0oc2F0LmZvcm11bGEsIGRhdGEgPSBpbmR1c3RyeV9jbGVhbmVkKQpgYGAKClNlbGVjdGluZyBTcGVjaWZpYyBEaWFnbm9zdGljIHBsb3RzIGZvciBsaW5lYXIgbW9kZWxzCmBgYHtyfQpwbG90KGluY29tZS5tb2RlbCwgd2hpY2ggPSAxKQpwbG90KGluY29tZS5tb2RlbCwgd2hpY2ggPSAyKQpwbG90KGluY29tZS5tb2RlbCwgd2hpY2ggPSAzKQpwbG90KGluY29tZS5tb2RlbCwgd2hpY2ggPSA1KQpgYGAKCgpDb3JyZWN0aW5nIHZpb2xhdGlvbiBvZiBOb3JtYWxpdHkgaW4gcHJldmlvdXMgbW9kZWwgd2l0aCBCb3hDb3ggdHJhbnNmb3JtCmBgYHtyfQpiY19mdW5jIDwtIGZ1bmN0aW9uIChsbS5jbGVhbmVkLCBsYW1iZGEucmFuZ2UpewogIGJjID0gYm94Q294KGxtLmNsZWFuZWQsIGxhbWJkYSA9IGxhbWJkYS5yYW5nZSkKICAjRXh0cmFjdGluZyB0aGUgYmVzdCBsYW1iZGEgdmFsdWUuCiAgcmV0dXJuKGJjJHhbd2hpY2goYmMkeSA9PSBtYXgoYmMkeSkpXSkKfQoKI0luY29tZSBHcm91cCBEYXRhc2V0CmluY29tZS5sYW1iZGEuYmMgPSBiY19mdW5jKGluY29tZS5tb2RlbCwgc2VxKC0wLjIsIDAuMiwgMS8xMCkpCmluY29tZS5sYW1iZGEuYmMKCiNJbmR1c3RyeSBHcm91cCBEYXRhc2V0CmluZHVzdHJ5LmxhbWJkYS5iYyA9IGJjX2Z1bmMoaW5kdXN0cnkubW9kZWwsIHNlcSgtMC4yLCAwLjIsIDEvMTApKQppbmR1c3RyeS5sYW1iZGEuYmMKCmJjX3RyYW5zZm9ybSA8LSBmdW5jdGlvbihkZiwgbGFtYmRhLmJjKXsKICByZXR1cm4gKGRmICU+JSAKICAgICAgICAgICAgbXV0YXRlKEF2Zy5iYyA9IChBdmdebGFtYmRhLmJjIC0xKS9sYW1iZGEuYmMpICU+JSAKICAgICAgICAgICAgc2VsZWN0KC1jKEF2ZykpKSAjdG9vayBvdXQgZmllbGQgQW1vdW50Cn0KCiNJbmNvbWUgR3JvdXAgRGF0YXNldAppbmNvbWVfY2xlYW5lZF9iYyA8LSBiY190cmFuc2Zvcm0oaW5jb21lX2NsZWFuZWQsIGluY29tZS5sYW1iZGEuYmMpCmluY29tZS5tb2RlbC5iYyA9IGxtKEF2Zy5iYyB+IC4sIGRhdGEgPSBpbmNvbWVfY2xlYW5lZF9iYykKCiNJbmR1c3RyeSBHcm91cCBEYXRhc2V0CmluZHVzdHJ5X2NsZWFuZWRfYmMgPC0gYmNfdHJhbnNmb3JtKGluZHVzdHJ5X2NsZWFuZWQsIGluZHVzdHJ5LmxhbWJkYS5iYykKaW5kdXN0cnkubW9kZWwuYmMgPSBsbShBdmcuYmMgfiAuLCBkYXRhID0gaW5kdXN0cnlfY2xlYW5lZF9iYykKYGBgCgpUZXN0aW5nIG91dCBhcHBlbmRpbmcgYSBuZXdseSBjcmVhdGVkIGRhdGFmcmFtZSB0byBhIGxpc3Qgb2YgZGF0YWZyYW1lcyB3aXRoIGEgTmFtZSBmb3IgU2hpbnkgYXBwCmBgYHtyfQojIGluY29tZV9jbGVhbmVkX2JjCiMgYWxsLmRhdGEgPC0gbGlzdCgnaW5jb21lX2NsZWFuZWQnID0gaW5jb21lX2NsZWFuZWQsICdpbmR1c3RyeV9jbGVhbmVkJyA9IGluZHVzdHJ5X2NsZWFuZWQpCiMgYWxsLmRhdGEgPC0gYXBwZW5kKGFsbC5kYXRhLCBsaXN0KCdpbmNvbWVfY2xlYW5lZF9iYycgPSBpbmNvbWVfY2xlYW5lZF9iYykpCiMgYWxsLmRhdGFbWydpbmNvbWVfY2xlYW5lZF9iYyddXQpgYGAKClRlc3Rpbmcgb3V0IGJjX2Z1bmMgZm9yIG1pZ3JhdGlvbiB0byBTaGlueSBBcHAgZ2xvYmFsLlIgZmlsZQpgYGB7cn0KYmNfZnVuY3QgPC0gZnVuY3Rpb24gKGRmLCBsbS5jbGVhbmVkLCBsYW1iZGEucmFuZ2UpewogIGJjID0gYm94Q294KGxtLmNsZWFuZWQsIGxhbWJkYSA9IGxhbWJkYS5yYW5nZSkKICBsYW1iZGEuYmMgPSBiYyR4W3doaWNoKGJjJHkgPT0gbWF4KGJjJHkpKV0KICByZXR1cm4oZGYgJT4lIAogICAgICAgICAgICBtdXRhdGUoQXZnLmJjID0gKEF2Z15sYW1iZGEuYmMgLTEpL2xhbWJkYS5iYykgJT4lIAogICAgICAgICAgICBzZWxlY3QoLWMoQXZnKSkpCn0KCmJjX2Z1bmN0KGluY29tZV9jbGVhbmVkLCBpbmNvbWUubW9kZWwsIHNlcSgtMC4yLCAwLjIsIDEvMTApKQpgYGAKYGBge3J9CmJjX2Z1bmMyIDwtIGZ1bmN0aW9uICgpewogIGJjID0gYm94Q294KGxtKEF2ZyB+IC4sIGRhdGEgPSBpbmR1c3RyeV9jbGVhbmVkKSwgbGFtYmRhID0gc2VxKC0wLjIsIDAuMiwgMS8xMCkpCiAgbGFtYmRhLmJjID0gYmMkeFt3aGljaChiYyR5ID09IG1heChiYyR5KSldCiAgcmV0dXJuKGluZHVzdHJ5X2NsZWFuZWQgJT4lCiAgICAgICAgICAgbXV0YXRlKEF2Zy5iYyA9IChBdmdebGFtYmRhLmJjIC0xKS9sYW1iZGEuYmMpICU+JQogICAgICAgICAgIHNlbGVjdCgtYyhBdmcpKSkKfQoKaW5kdXN0cnlfY2xlYW5lZF9iYyA8LWJjX2Z1bmMyKCkKaW5kdXN0cnlfY2xlYW5lZF9iYwpgYGAKCkNoZWNraW5nIGxpbmVhciByZWdyZXNzaW9uIGFzc3VtcHRpb25zIGZvciB0aGUgdHJhbnNmb3JtZWQgZGF0YS4KYGBge3J9CnNhdC5mb3JtdWxhLmJjIDwtIEF2Zy5iYyB+IC4Kc2F0LmZpZWxkLmJjIDwtICdBdmcuYmMnCgojSW5jb21lCnNhdC5tb2RlbC5zdW1tYXJ5KGluY29tZV9jbGVhbmVkX2JjLCBzYXQuZmllbGQuYmMsIHNhdC5mb3JtdWxhLmJjKQoKI0luZHVzdHJ5CnNhdC5tb2RlbC5zdW1tYXJ5KGluZHVzdHJ5X2NsZWFuZWRfYmMsIHNhdC5maWVsZC5iYywgc2F0LmZvcm11bGEuYmMpCmBgYAoKYGBge3J9CmF2UGxvdHMoaW5jb21lLm1vZGVsLmJjKQpgYGAKCkJJQyBjb21wYXJpc29uIGJlZm9yZSBhbmQgYWZ0ZXIgQm94Q294IHRyYW5zZm9ybQpgYGB7cn0KQklDKGluY29tZS5tb2RlbC5iYywgaW5jb21lLm1vZGVsKQpCSUMoaW5kdXN0cnkubW9kZWwuYmMsIGluZHVzdHJ5Lm1vZGVsKQpgYGAKClN0ZXB3aXNlIFJlZ3Jlc3Npb24gb24gSW5jb21lX2NhdF9iYyAoYm94Y294IHRyYW5zZm9ybWVkIGRhdGFzZXQpCmBgYHtyfQojY3JlYXRpbmcgZHVtbXkgdmFyaWFibGUgY29sdW1ucyBmb3Igc3RlcHdpc2UKZHVtbXlfZnVuYyA8LSBmdW5jdGlvbiAoZGYpewogIHggPSBtb2RlbC5tYXRyaXgoQXZnLmJjIH4uLCBkZilbLCAtMV0KICBkdW1teV9iYyA9IGFzLmRhdGEuZnJhbWUoeCkgJT4lIG11dGF0ZShBdmcuYmMgPSBkZiRBdmcuYmMpCiAgI2NvbG5hbWVzKGR1bW15X2JjKSA8LSBzdHJfcmVwbGFjZV9hbGwoY29sbmFtZXMoZHVtbXlfYmMpLCAiLXwnfC98IHwsfO+/vXwmIiAsICdfJykKICBjb2xuYW1lcyhkdW1teV9iYykgPC0gc3RyX3JlcGxhY2VfYWxsKGNvbG5hbWVzKGR1bW15X2JjKSwgIlstJy8gLO+/vSYoKWBdIiAsICdfJykKICByZXR1cm4oZHVtbXlfYmMpCn0KYGBgCgpDbGVhbmluZyBjb2x1bW4gbmFtZXMgZnVydGhlciBzbyBzdGVwd2lzZSByZWdyZXNzaW9uIGRvZXNuJ3QgcHJlc2VudCBhbnkgZXJyb3JzCmBgYHtyfQojSW5jb21lIEdyb3VwIERhdGFzZXQKaW5jb21lLmR1bW15LmJjIDwtIGR1bW15X2Z1bmMoaW5jb21lX2NsZWFuZWRfYmMpCiNjb2xuYW1lcyhpbmNvbWUuZHVtbXkuYmMpWzM3XSA8LSAnTmFtZU1hbnVmYWN0dXJlcnUwMDkyc19SZWFsX1Byb3BlcnR5X1RheF9DcmVkaXQnCmNvbG5hbWVzKGluY29tZS5kdW1teS5iYykKCiNJbmR1c3RyeSBHcm91cCBEYXRhc2V0CmluZHVzdHJ5LmR1bW15LmJjIDwtIGR1bW15X2Z1bmMoaW5kdXN0cnlfY2xlYW5lZF9iYykKI2NvbG5hbWVzKGluZHVzdHJ5LmR1bW15LmJjKVszNV0gPC0gJ05hbWVNYW51ZmFjdHVyZXJ1MDA5MnNfUmVhbF9Qcm9wZXJ0eV9UYXhfQ3JlZGl0Jwpjb2xuYW1lcyhpbmR1c3RyeS5kdW1teS5iYykKYGBgCgpTdGVwd2lzZSByZWdyZXNzaW9uIHVzaW5nIEJJQyBhcyB0aGUgY3JpdGVyaWEgKGsgPSBsb2cobikpLgpgYGB7cn0KI0NyZWF0aW5nIFN0ZXB3aXNlIE1vZGVscwpiY3MgPSBsaXN0KGluY29tZSA9IGluY29tZS5kdW1teS5iYywgaW5kdXN0cnkgPSBpbmR1c3RyeS5kdW1teS5iYykKbW9kZWwuZnVsbHMgPSBsaXN0KGluY29tZSA9IGxtKEF2Zy5iYyB+IC4sIGRhdGEgPSBpbmNvbWUuZHVtbXkuYmMpLCBpbmR1c3RyeSA9IGxtKEF2Zy5iYyB+IC4sIGRhdGEgPSBpbmR1c3RyeS5kdW1teS5iYykpICNBbGwgdmFyaWFibGVzCm1vZGVsLmVtcHR5cyA9IGxpc3QoaW5jb21lID0gbG0oQXZnLmJjIH4gMSwgZGF0YSA9IGluY29tZS5kdW1teS5iYyksIGluZHVzdHJ5ID0gbG0oQXZnLmJjIH4gMSwgZGF0YSA9IGluZHVzdHJ5LmR1bW15LmJjKSkgI2ludGVyY2VwdCBvbmx5CmsgPSBjKCdpbmNvbWUnLCAnaW5kdXN0cnknKQpmb3J3YXJkQklDID0gbGlzdChpbmNvbWUgPSBOVUxMLCBpbmR1c3RyeSA9IE5VTEwpCmJhY2t3YXJkQklDID0gbGlzdChpbmNvbWUgPSBOVUxMLCBpbmR1c3RyeSA9IE5VTEwpCgpmb3IgKGkgaW4gayl7CiAgYmMgPSBiY3NbW2ldXQogIHNjb3BlID0gbGlzdChsb3dlciA9IGZvcm11bGEobW9kZWwuZW1wdHlzW1tpXV0pLCB1cHBlciA9IGZvcm11bGEobW9kZWwuZnVsbHNbW2ldXSkpCiAgbl9vYnMgPSBiYyAlPiUgY291bnQoKSAlPiUgZHBseXI6OmZpcnN0KCkKICBmb3J3YXJkQklDW1tpXV0gPSBzdGVwKG1vZGVsLmVtcHR5c1tbaV1dLCBzY29wZSwgZGlyZWN0aW9uID0gImZvcndhcmQiLCBrID0gbG9nKG5fb2JzKSkKICBiYWNrd2FyZEJJQ1tbaV1dID0gc3RlcChtb2RlbC5mdWxsc1tbaV1dLCBzY29wZSwgZGlyZWN0aW9uID0gImJhY2t3YXJkIiwgayA9IGxvZyhuX29icykpCn0KYGBgCgpTZWxlY3RpbmcgQmVzdCBGb3JtdWxhIHBlciBEYXRhc2V0IGZyb20gU3RlcHdpc2UgUmVncmVzc2lvbnMKYGBge3J9CmJpY19mdW5jIDwtIGZ1bmN0aW9uIChCSUMubW9kZWwpewogIHByaW50KCdBZGp1c3RlZCBSIFNxdWFyZWQ6JykKICBwcmludChzdW1tYXJ5KEJJQy5tb2RlbCkkYWRqLnIuc3F1YXJlZCkKICBwcmludCgnTnVtYmVyIG9mIENvZWZmaWNpZW50czonKQogIHByaW50KGRpbShzdW1tYXJ5KEJJQy5tb2RlbCkkY29lZmZpY2llbnQpWzFdKQogIHByaW50KCdWSUYgQ2hlY2s6ICcpCiAgcHJpbnQobWF4KHZpZihCSUMubW9kZWwpKSkKICBwcmludCgiKioqKioqKioqKioqKioqKioqKioqKioqKiIpCiAgcmV0dXJuKGMoc3VtbWFyeShCSUMubW9kZWwpJGFkai5yLnNxdWFyZWQsIGRpbShzdW1tYXJ5KEJJQy5tb2RlbCkkY29lZmZpY2llbnQpWzFdLCBtYXgodmlmKEJJQy5tb2RlbCkpKSkKfQoKYXMuZGF0YS5mcmFtZShyYmluZChjKCdpbmNvbWUnLCAnZm9yd2FyZCcsIGJpY19mdW5jKGZvcndhcmRCSUNbWydpbmNvbWUnXV0pKSwKICAgICAgYygnaW5jb21lJywgJ2JhY2t3YXJkJywgYmljX2Z1bmMoYmFja3dhcmRCSUNbWydpbmNvbWUnXV0pKSwKICAgICAgYygnaW5kdXN0cnknLCAnZm9yd2FyZCcsIGJpY19mdW5jKGZvcndhcmRCSUNbWydpbmR1c3RyeSddXSkpLAogICAgICBjKCdpbmR1c3RyeScsICdiYWNrd2FyZCcsIGJpY19mdW5jKGJhY2t3YXJkQklDW1snaW5kdXN0cnknXV0pKQogICAgICApCikgJT4lIHNlbGVjdChkYXRhc2V0ID0gVjEsIFN0ZXB3aXNlID0gVjIsIGBBZGp1c3RlZCBSXjJgID0gVjMsIGBOdW1iZXIgb2YgQ29lZmZpY2llbnRzYCA9IFY0LCBgTWF4aW11bSBWSUZgID0gVjUpICU+JSB3cml0ZV9jc3YoJ1NoaW55X2FwcC9kYXRhL3N0ZXB3aXNlQklDX3Jlc3VsdHMuY3N2JykKCmJpY19mdW5jKGZvcndhcmRCSUNbWydpbmNvbWUnXV0pCmJpY19mdW5jKGJhY2t3YXJkQklDW1snaW5jb21lJ11dKQpiaWNfZnVuYyhmb3J3YXJkQklDW1snaW5kdXN0cnknXV0pIApiaWNfZnVuYyhiYWNrd2FyZEJJQ1tbJ2luZHVzdHJ5J11dKQoKI01hbnVhbCByZWR1Y3Rpb24gb2YgdmFyaWFibGVzIHVzaW5nIFZJRiBhbmQgdGhlbiBjaGVja2VkIHZlcnN1cyBzYXR1cmF0ZWQgbW9kZWwgd2l0aCBBbm92YS4gVGhpcyB3YXMgbm90IHVzZWQgYmVjYXVzZSB0aGUgc2F0dXJhdGVkIG1vZGVsIGNvbnRhaW5lZCBtdWx0aWNvbGxpbmVhcml0eSBpc3N1ZXMgYXMgaW5kaWNhdGVkIGJ5IGEgaGlnaCBWSUYgc2NvcmUgb24gc29tZSBjb2VmZmljaWVudHMuIEFuZCB0aGUgYW5vdmEgdGVzdCBzdWdnZXN0ZWQgdGhhdCB0aGUgY29lZmZpY2llbnRzIHJlbW92ZWQgaW4gdGhlIHJlZHVjZWQgbW9kZWwgd2VyZSBpbmZvcm1hdGl2ZSBpbiBvdXIgbW9kZWwsIHNvIHdlIGNvdWxkbid0IHVzZSBpdCBlaXRoZXIuIFRodXMgU3RlcHdpc2UgcmVkdWN0aW9uIGlzIHRoZSBwcmVmZXJyZWQgbWV0aG9kIGZvciBiZXN0IG1vZGVsIGZpdC4KCiMgVklGLnZhcmlhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHZpZihtb2RlbC5mdWxsc1tbJ2luZHVzdHJ5J11dKSkgJT4lIAojICAgc2VsZWN0KFZJRiA9IGB2aWYobW9kZWwuZnVsbHNbWyJpbmR1c3RyeSJdXSlgKSAlPiUgCiMgICBmaWx0ZXIoVklGID4gNSkgJT4lIHJvd25hbWVzKCkKIyAKIyBpbmR1c3RyeS5kdW1teS5iYy5WSUYgPC0gaW5kdXN0cnkuZHVtbXkuYmMgJT4lIHNlbGVjdCgtYWxsX29mKFZJRi52YXJpYWJsZXMpKQojIGluZHVzdHJ5Lm1vZGVsLlZJRiA8LSBsbShBdmcuYmMgfiAuLCBkYXRhID0gaW5kdXN0cnkuZHVtbXkuYmMuVklGKQojIHN1bW1hcnkoaW5kdXN0cnkubW9kZWwuVklGKQojIGFub3ZhKGluZHVzdHJ5Lm1vZGVsLlZJRiwgbW9kZWwuZnVsbHNbWydpbmR1c3RyeSddXSkKCmBgYAoKQmVzdCBNb2RlbCBTZWxlY3Rpb24gZnJvbSBTdGVwd2lzZQpgYGB7cn0KI1RoZSBCZXN0IE1vZGVscyBzZWxlY3RlZCBmb3IgYm90aCBpbmNvbWUgYW5kIGluZHVzdHJ5IHdlcmUgZm9yd2FyZEJJQy4KCiNJbmNvbWUgR3JvdXAgRGF0YXNldAppbmNvbWUuYmVzdC5mb3JtdWxhIDwtIGZvcndhcmRCSUNbWydpbmNvbWUnXV0kY2FsbFtbMl1dCmluY29tZS5iZXN0LmZvcm11bGEKCiNJbmR1c3RyeSBHcm91cCBEYXRhc2V0CmluZHVzdHJ5LmJlc3QuZm9ybXVsYSA8LSBmb3J3YXJkQklDW1snaW5kdXN0cnknXV0kY2FsbFtbMl1dCmluZHVzdHJ5LmJlc3QuZm9ybXVsYQpgYGAKCgpTcGxpdHRpbmcgZGF0YSB1cCBpbnRvIHRlc3QgZGF0YSBhbmQgdHJhaW5pbmcgZGF0YSAodGVzdCBkYXRhIGlzIGZvciB5ZWFyIDIwMTksIHRyYWluaW5nIGlzIHRoZSByZXN0KQpgYGB7cn0KdGVzdF90cmFpbl9zcGxpdCA8LSBmdW5jdGlvbihkdW1teV9iYywgYmVzdC5mb3JtdWxhKSB7CiAgIyBkYXRhLnRlc3QgPC0gZHVtbXlfYmMgJT4lIGZpbHRlcihZZWFyID09IDIwMTkpCiAgIyBkYXRhLnRyYWluIDwtIGR1bW15X2JjICU+JSBmaWx0ZXIoWWVhciAhPSAyMDE5KQogIFggPC0gbW9kZWwubWF0cml4KGJlc3QuZm9ybXVsYSwgZGF0YSA9IGR1bW15X2JjKVssLTFdCiAgeSA8LSBhcy5tYXRyaXgoZHVtbXlfYmMgJT4lIHNlbGVjdChhbGwudmFycyhiZXN0LmZvcm11bGEpWzFdKSkKICAKICBzZXQuc2VlZCgwKQogIHRyYWluLmkgPSBzYW1wbGUoMTpucm93KGR1bW15X2JjKSwgMC44Km5yb3coZHVtbXlfYmMpLCByZXBsYWNlID0gRikKICAKICAjdHJhaW4KICBYLnRyYWluIDwtIFhbdHJhaW4uaSxdCiAgeS50cmFpbiA8LSB5W3RyYWluLmksXQogIAogICN0ZXN0CiAgWC50ZXN0IDwtIFhbLXRyYWluLmksXQogIHkudGVzdCA8LSB5Wy10cmFpbi5pLF0KICAKICBkYXRhLnRyYWluIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoeS50cmFpbiwgWC50cmFpbikpCiAgZGF0YS50ZXN0IDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoeS50ZXN0LCBYLnRlc3QpKQogIGNvbG5hbWVzKGRhdGEudHJhaW4pWzFdID0gYWxsLnZhcnMoYmVzdC5mb3JtdWxhKVsxXQogIGNvbG5hbWVzKGRhdGEudGVzdClbMV0gPSBhbGwudmFycyhiZXN0LmZvcm11bGEpWzFdCiAgCiAgcmV0dXJuIChsaXN0KCdYLnRyYWluJyA9IFgudHJhaW4sICd5LnRyYWluJyA9IHkudHJhaW4sICdYLnRlc3QnID0gWC50ZXN0LCAneS50ZXN0JyA9IHkudGVzdCwgJ2RhdGEudHJhaW4nID0gZGF0YS50cmFpbiwgJ2RhdGEudGVzdCcgPSBkYXRhLnRlc3QpKQp9CmBgYAoKYGBge3J9CnRlc3RfdHJhaW5fc3BsaXRfb2xkIDwtIGZ1bmN0aW9uKGR1bW15X2JjLCBiZXN0LmZvcm11bGEpIHsKICAjIGRhdGEudGVzdCA8LSBkdW1teV9iYyAlPiUgZmlsdGVyKFllYXIgPT0gMjAxOSkKICAjIGRhdGEudHJhaW4gPC0gZHVtbXlfYmMgJT4lIGZpbHRlcihZZWFyICE9IDIwMTkpCiAgc2V0LnNlZWQoMCkKICB0cmFpbi5pID0gc2FtcGxlKDE6bnJvdyhkdW1teV9iYyksIDAuOCpucm93KGR1bW15X2JjKSwgcmVwbGFjZSA9IEYpCiAgZGF0YS50cmFpbiA8LSBkdW1teV9iYyAlPiUgc2xpY2UodHJhaW4uaSkKICBkYXRhLnRlc3QgPC0gZHVtbXlfYmMgJT4lIHNsaWNlKC10cmFpbi5pKQogIAogICN0cmFpbgogICNYLnRyYWluIDwtIGFzLm1hdHJpeChkYXRhLnRyYWluICU+JSBzZWxlY3QoLUF2Zy5iYykpCiAgWC50cmFpbiA8LSBtb2RlbC5tYXRyaXgoYmVzdC5mb3JtdWxhLCBkYXRhID0gZGF0YS50cmFpbilbLC0xXQogIHkudHJhaW4gPC0gYXMubWF0cml4KGRhdGEudHJhaW4gJT4lIHNlbGVjdChhbGwudmFycyhiZXN0LmZvcm11bGEpWzFdKSkKCiAgI3Rlc3QKICAjWC50ZXN0IDwtIGFzLm1hdHJpeChkYXRhLnRlc3QgJT4lIHNlbGVjdCgtQXZnLmJjKSkKICBYLnRlc3QgPC0gbW9kZWwubWF0cml4KGJlc3QuZm9ybXVsYSwgZGF0YSA9IGRhdGEudGVzdClbLC0xXQogIHkudGVzdCA8LSBhcy5tYXRyaXgoZGF0YS50ZXN0ICU+JSBzZWxlY3QoYWxsLnZhcnMoYmVzdC5mb3JtdWxhKVsxXSkpCiAgCiAgI3JldHVybiAobGlzdCgnWC50cmFpbicgPSBYLnRyYWluLCAneS50cmFpbicgPSB5LnRyYWluLCAnWC50ZXN0JyA9IFgudGVzdCwgJ3kudGVzdCcgPSB5LnRlc3QsICdkYXRhLnRyYWluJyA9IGRhdGEudHJhaW4sICdkYXRhLnRlc3QnID0gZGF0YS50ZXN0KSkKfQoKI0luY29tZQppbmNvbWUuZGF0YS5zcGxpdC5zYXQgPC0gdGVzdF90cmFpbl9zcGxpdChpbmNvbWUuZHVtbXkuYmMsIEF2Zy5iYyB+IC4pCmluY29tZS5kYXRhLnNwbGl0IDwtIHRlc3RfdHJhaW5fc3BsaXQoaW5jb21lLmR1bW15LmJjLCBpbmNvbWUuYmVzdC5mb3JtdWxhKQoKI0luZHVzdHJ5CmluZHVzdHJ5LmRhdGEuc3BsaXQuc2F0IDwtIHRlc3RfdHJhaW5fc3BsaXQoaW5kdXN0cnkuZHVtbXkuYmMsIEF2Zy5iYyB+IC4pCmluZHVzdHJ5LmRhdGEuc3BsaXQgPC0gdGVzdF90cmFpbl9zcGxpdChpbmR1c3RyeS5kdW1teS5iYywgaW5kdXN0cnkuYmVzdC5mb3JtdWxhKQoKdGVzdF90cmFpbl9zcGxpdChpbmNvbWVfY2xlYW5lZCwgc2F0LmZvcm11bGEpCmBgYAoKCkxhc3NvIHJlZ3Jlc3Npb24gZm9yIGNvbXBhcmlzb24gdG8gRm9yd2FyZCBTdGVwd2lzZQpgYGB7cn0KIyBjYWxjX01TRSA8LSBmdW5jdGlvbiAobW9kZWwsIHgudGVzdCwgeS50ZXN0KXsKIyAgIHkucHJlZGljdCA8LSBwcmVkaWN0KG1vZGVsLCBuZXdkYXRhID0geC50ZXN0KQojICAgcmV0dXJuKG1lYW4oKHkucHJlZGljdCAtIHkudGVzdCleMikpCiMgfQoKIyB4eS5zcGxpdHMgPC0gbGlzdCgnaW5jb21lJyA9IGluY29tZS5kYXRhLnNwbGl0LCAKIyAgICAgICAgICAgICAgICAgICAnaW5kdXN0cnknID0gaW5kdXN0cnkuZGF0YS5zcGxpdCwgCiMgICAgICAgICAgICAgICAgICAgJ2luY29tZS5zYXQnID0gaW5jb21lLmRhdGEuc3BsaXQuc2F0LCAKIyAgICAgICAgICAgICAgICAgICAnaW5kdXN0cnkuc2F0JyA9IGluZHVzdHJ5LmRhdGEuc3BsaXQuc2F0KQojIAojIGxhc3NvLmxpc3QgPC0gYygnaW5jb21lJywgJ2luZHVzdHJ5JywgJ2luY29tZS5zYXQnLCAnaW5kdXN0cnkuc2F0JykKIyBiYXNlbGluZS5saXN0IDwtIGMoJ2luY29tZS5zYXQnLCAnaW5kdXN0cnkuc2F0JywgJ2luY29tZS5zYXQnLCAnaW5kdXN0cnkuc2F0JykKIyByaWRnZS5hbHBoYSA8LSAwCiMgCiMgZm9yIChhIGluIDE6NCl7CiMgICBpID0gbGFzc28ubGlzdFthXQojICAgYiA9IGJhc2VsaW5lLmxpc3RbYV0KIyAgIFgudHJhaW4gPC0geHkuc3BsaXRzW1tpXV1bWydYLnRyYWluJ11dCiMgICB5LnRyYWluIDwtIHh5LnNwbGl0c1tbaV1dW1sneS50cmFpbiddXQojICAgWC50ZXN0IDwtIHh5LnNwbGl0c1tbaV1dW1snWC50ZXN0J11dCiMgICB5LnRlc3QgPC0geHkuc3BsaXRzW1tpXV1bWyd5LnRlc3QnXV0KIyAgIFgudGVzdC5zYXQgPC0geHkuc3BsaXRzW1tiXV1bWydYLnRlc3QnXV0KIyAgIHkudGVzdC5zYXQgPC0geHkuc3BsaXRzW1tiXV1bWyd5LnRlc3QnXV0KIyAgIGRhdGEudHJhaW4gPC0geHkuc3BsaXRzW1tpXV1bWydkYXRhLnRyYWluJ11dCiMgICBkYXRhLnRlc3QgPC0geHkuc3BsaXRzW1tpXV1bWydkYXRhLnRlc3QnXV0KIyAgIAojICAgI2NyZWF0ZSBsYW1iZGEgZ3JpZAojICAgbGFtYmRhLmdyaWQgPSAxMF5zZXEoMiwgLTUsIGxlbmd0aCA9IDEwMCkKIyAgIAojICAgI2NyZWF0ZSBsYXNzbyBtb2RlbHMgd2l0aCBsYW1iZGEuZ3JpZAojICAgbGFzc28ubW9kZWxzID0gZ2xtbmV0KFgudHJhaW4sIHkudHJhaW4sIGFscGhhID0gcmlkZ2UuYWxwaGEsIGxhbWJkYSA9IGxhbWJkYS5ncmlkKQojICAgCiMgICAjdmlzdWFsaXplIGNvZWZmaWNpZW50IHNocmlua2FnZQojICAgcGxvdChsYXNzby5tb2RlbHMsIHh2YXIgPSAibGFtYmRhIiwgbGFiZWwgPSBUUlVFLCBtYWluID0gcGFzdGUoIkxhc3NvIFJlZ3Jlc3Npb246IiwgaSkpCiMgICAKIyAgICNDcm9zcyBWYWxpZGF0aW9uIHRvIGZpbmQgYmVzdCBsYW1iZGEKIyAgIHNldC5zZWVkKDApCiMgICBjdi5sYXNzby5tb2RlbHMgPC0gY3YuZ2xtbmV0KFgudHJhaW4sIHkudHJhaW4sIGFscGhhID0gcmlkZ2UuYWxwaGEsIGxhbWJkYSA9IGxhbWJkYS5ncmlkLCBuZm9sZHMgPSAxMCkKIyAgIAojICAgI3Zpc3VhbGl6ZSBjcm9zcyB2YWxpZGF0aW9uIGZvciBsYW1iZGEgdGhhdCBtaW5pbWl6ZXMgdGhlIG1lYW4gc3F1YXJlZCBlcnJvci4KIyAgIHBsb3QoY3YubGFzc28ubW9kZWxzLCBtYWluID0gcGFzdGUoIkxhc3NvIFJlZ3Jlc3Npb246IiwgaSkpCiMgICAKIyAgICNDaGVja2luZyB0aGUgYmVzdCBsYW1iZGEKIyAgIGxvZyhjdi5sYXNzby5tb2RlbHMkbGFtYmRhLm1pbikKIyAgIGJlc3QubGFtYmRhIDwtIGN2Lmxhc3NvLm1vZGVscyRsYW1iZGEubWluCiMgICBwcmludChwYXN0ZShpLCAnIGJlc3QubGFtYmRhOicsIGJlc3QubGFtYmRhKSkKIyAgICMgYmVzdCBsYW1iZGEgd2l0aCBhbGwgdGhlIHZhcmlhYmxlcyB3YXMgZm91bmQgdG8gYmUgMC4wMDA2ODkyNjEyCiMgICAjIGJlc3QgbGFtYmRhIHdpdGggb25seSB0aGUgYndkQklDIGNvZWZmaWNpZW50cyBpbmNsdWRlZCB3YXMgZm91bmQgdG8gYmUgMC4wMDAzMDUzODU2CiMgICAKIyAgICNsb29raW5nIGF0IHRoZSBsYXNzbyBjb2VmZmljaWVudHMgZm9yIHRoZSBiZXN0LmxhbWJkYQojICAgYmVzdC5sYW1iZGEuY29lZmYgPC0gcHJlZGljdChsYXNzby5tb2RlbHMsIHMgPSBiZXN0LmxhbWJkYSwgdHlwZSA9ICJjb2VmZmljaWVudHMiKQojICAgcHJpbnQoJ051bWJlciBvZiBDb2VmZmljaWVudHM6JykKIyAgIHByaW50KGRpbShiZXN0LmxhbWJkYS5jb2VmZilbMV0pCiMgICAKIyAgICNmaXR0aW5nIGEgbW9kZWwgd2l0aCB0aGUgYmVzdCBsYW1iZGEgZm91bmQgdG8gYmUgMC4wMDA2ODkgYW5kIHVzaW5nIGl0IHRvIG1ha2UgcHJlZGljdGlvbnMgZm9yIHRoZSB0ZXN0aW5nIGRhdGEuCiMgICBsYXNzby5iZXN0LmxhbWJkYS50cmFpbi5wcmVkIDwtIHByZWRpY3QobGFzc28ubW9kZWxzLCBzID0gYmVzdC5sYW1iZGEsIG5ld3ggPSBYLnRlc3QpCiMgICBsYXNzby5iZXN0LmxhbWJkYS50cmFpbi5wcmVkCiMgICAKIyAgICNjaGVja2luZyBNU0UKIyAgIE1TRS5sYXNzbyA8LSBtZWFuKChsYXNzby5iZXN0LmxhbWJkYS50cmFpbi5wcmVkIC0geS50ZXN0KV4yKQojICAgc2F0Lm1vZGVsLmJjIDwtIGxtKEF2Zy5iYyB+LiwgZGF0YSA9IGRhdGEudHJhaW4pCiMgICAKIyAgIAojICAgdGVtcC5kZiA8LSBhcy5kYXRhLmZyYW1lKFgudGVzdC5zYXQpICN0ZW1wIGZpeAojICAgY29sbmFtZXModGVtcC5kZikgPC0gc3RyX3JlcGxhY2VfYWxsKGNvbG5hbWVzKHRlbXAuZGYpLCAiW2BdIiwgJycpCiMgICAKIyAgIHkucHJlZGljdCA8LSBwcmVkaWN0KHNhdC5tb2RlbC5iYywgbmV3ZGF0YSA9IHRlbXAuZGYpCiMgICBNU0Uuc2F0IDwtIG1lYW4oKHkucHJlZGljdCAtIHkudGVzdC5zYXQpXjIpCiMgICAKIyAgIHByaW50KHBhc3RlKGksICcgTGFzc28gTVNFOiAnLCBNU0UubGFzc28sICcgJywgYiwgJyBTYXR1cmF0ZWQgTVNFOiAnLCBNU0Uuc2F0KSkKIyAKIyAgIG1ldHJpY3MgPC0gZXZhbF9yZXN1bHRzKHkudGVzdCwgbGFzc28uYmVzdC5sYW1iZGEudHJhaW4ucHJlZCwgZGF0YS50ZXN0KQojICAgcHJpbnQobWV0cmljcykKIyAgIHByaW50KCcqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKicpCiMgfQpgYGAKCkZ1bmN0aW9uIHRvIHNob3cgbWV0cmljcyAoUl4yIGFuZCBNU0UpIGZvciBSZWd1bGFyaXphdGlvbiAoUmlkZ2UvTGFzc28pCmBgYHtyfQpyZWd1bGFyaXphdGlvbl9mdW5jIDwtIGZ1bmN0aW9uIChkYXRhLCBhbHBoYSwgbmFtZSl7CiAgWC50cmFpbiA8LSBkYXRhW1snWC50cmFpbiddXQogIHkudHJhaW4gPC0gZGF0YVtbJ3kudHJhaW4nXV0KICBYLnRlc3QgPC0gZGF0YSBbWydYLnRlc3QnXV0KICB5LnRlc3QgPC0gZGF0YVtbJ3kudGVzdCddXQogIGRhdGEudGVzdCA8LSBkYXRhW1snZGF0YS50ZXN0J11dCiAgIyBwcmludChjb2xuYW1lcyhYLnRyYWluKSkKICAjIHByaW50KGNvbG5hbWVzKFgudGVzdCkpCiAgIyBwcmludChzZXRkaWZmKGNvbG5hbWVzKFgudHJhaW4pLCBjb2xuYW1lcyhYLnRlc3QpKSkKICAKICAjY3JlYXRlIGxhbWJkYSBncmlkCiAgbGFtYmRhLmdyaWQgPSAxMF5zZXEoMTAsIC0xMCwgbGVuZ3RoID0gMTAwKQogIAogICNjcmVhdGUgbGFzc28gbW9kZWxzIHdpdGggbGFtYmRhLmdyaWQKICBsYXNzby5tb2RlbHMgPSBnbG1uZXQoWC50cmFpbiwgeS50cmFpbiwgYWxwaGEgPSBhbHBoYSwgbGFtYmRhID0gbGFtYmRhLmdyaWQpCiAgCiAgI3Zpc3VhbGl6ZSBjb2VmZmljaWVudCBzaHJpbmthZ2UKICAjIHBsb3QobGFzc28ubW9kZWxzLCB4dmFyID0gImxhbWJkYSIsIGxhYmVsID0gVFJVRSwgbWFpbiA9IHBhc3RlKCJMYXNzbyBSZWdyZXNzaW9uOiIsIGkpKQogIAogICNDcm9zcyBWYWxpZGF0aW9uIHRvIGZpbmQgYmVzdCBsYW1iZGEKICBzZXQuc2VlZCgwKQogIGN2Lmxhc3NvLm1vZGVscyA8LSBjdi5nbG1uZXQoWC50cmFpbiwgeS50cmFpbiwgYWxwaGEgPSBhbHBoYSwgbGFtYmRhID0gbGFtYmRhLmdyaWQsIG5mb2xkcyA9IDEwKQogIAogICN2aXN1YWxpemUgY3Jvc3MgdmFsaWRhdGlvbiBmb3IgbGFtYmRhIHRoYXQgbWluaW1pemVzIHRoZSBtZWFuIHNxdWFyZWQgZXJyb3IuCiAgcGxvdChjdi5sYXNzby5tb2RlbHMsIG1haW4gPSBwYXN0ZSgiQWxwaGE6IiwgYWxwaGEsICJSZWdyZXNzaW9uOiIsIG5hbWUpKQogIAogICNDaGVja2luZyB0aGUgYmVzdCBsYW1iZGEKICAjIGxvZyhjdi5sYXNzby5tb2RlbHMkbGFtYmRhLm1pbikKICAjIGJlc3QubGFtYmRhIDwtIGN2Lmxhc3NvLm1vZGVscyRsYW1iZGEubWluCiAgIyBwcmludChwYXN0ZShpLCAnIGJlc3QubGFtYmRhOicsIGJlc3QubGFtYmRhKSkKICAjIGJlc3QgbGFtYmRhIHdpdGggYWxsIHRoZSB2YXJpYWJsZXMgd2FzIGZvdW5kIHRvIGJlIDAuMDAwNjg5MjYxMgogICMgYmVzdCBsYW1iZGEgd2l0aCBvbmx5IHRoZSBid2RCSUMgY29lZmZpY2llbnRzIGluY2x1ZGVkIHdhcyBmb3VuZCB0byBiZSAwLjAwMDMwNTM4NTYKICAKICAjbG9va2luZyBhdCB0aGUgbGFzc28gY29lZmZpY2llbnRzIGZvciB0aGUgYmVzdC5sYW1iZGEKICAjIGJlc3QubGFtYmRhLmNvZWZmIDwtIHByZWRpY3QobGFzc28ubW9kZWxzLCBzID0gY3YubGFzc28ubW9kZWxzJGxhbWJkYS5taW4sIHR5cGUgPSAiY29lZmZpY2llbnRzIikKICAjIHByaW50KCdOdW1iZXIgb2YgQ29lZmZpY2llbnRzOicpCiAgIyBwcmludChkaW0oYmVzdC5sYW1iZGEuY29lZmYpWzFdKQogIAogICNmaXR0aW5nIGEgbW9kZWwgd2l0aCB0aGUgYmVzdCBsYW1iZGEgZm91bmQgdG8gYmUgMC4wMDA2ODkgYW5kIHVzaW5nIGl0IHRvIG1ha2UgcHJlZGljdGlvbnMgZm9yIHRoZSB0ZXN0aW5nIGRhdGEuCiAgbGFzc28uYmVzdC5sYW1iZGEudHJhaW4ucHJlZCA8LSBwcmVkaWN0KGxhc3NvLm1vZGVscywgcyA9IGN2Lmxhc3NvLm1vZGVscyRsYW1iZGEubWluLCBuZXd4ID0gWC50ZXN0KQogIGxhc3NvLmJlc3QubGFtYmRhLnRyYWluLnByZWQKICAKICAjY2hlY2tpbmcgTVNFCiAgTVNFLmxhc3NvIDwtIG1lYW4oKGxhc3NvLmJlc3QubGFtYmRhLnRyYWluLnByZWQgLSB5LnRlc3QpXjIpCiAgcHJpbnQocGFzdGUoJ0RpbWVuc2lvbnMgb2YgdGhlIEFscGhhOicsIGFscGhhLCAnIFJlZ3Jlc3Npb24gQ29lZmZpY2llbnRzIGZvcjonLCBuYW1lKSkKICBwcmludChkaW0oY29lZihsYXNzby5tb2RlbHMpKVsxXSkKICBwID0gZGltKGNvZWYobGFzc28ubW9kZWxzKSlbMV0KICByZXR1cm4oZXZhbF9yZXN1bHRzKHkudGVzdCwgbGFzc28uYmVzdC5sYW1iZGEudHJhaW4ucHJlZCwgZGF0YS50ZXN0LCBwKVsnUnNxdWFyZSddKQp9CgpyZWd1bGFyaXphdGlvbl9mdW5jKGFsbC5zcGxpdHNbWydpbmNvbWVfY2xlYW5lZCddXSwgMCwgJ2luY29tZV9jbGVhbmVkJykKcmVndWxhcml6YXRpb25fZnVuYyhhbGwuc3BsaXRzW1snaW5jb21lX2NsZWFuZWRfYmMnXV0sIDAsICdpbmNvbWVfY2xlYW5lZF9iYycpCnJlZ3VsYXJpemF0aW9uX2Z1bmMoYWxsLnNwbGl0c1tbJ2luY29tZS5kYXRhLnNwbGl0LnNhdCddXSwgMCwgJ2luY29tZS5kYXRhLnNwbGl0LnNhdCcpCgpgYGAKCgpgYGB7cn0KI2FsbC5kZnMgPC0gbGlzdChpbmNvbWVfY2xlYW5lZCwgaW5jb21lX2NsZWFuZWRfYmMsIGluY29tZS5kdW1teS5iYykKCmZvcm11bGFzIDwtIGxpc3QoaW5jb21lX2NsZWFuZWQgPSBzYXQuZm9ybXVsYSwgCiAgICAgICAgICAgICAgICAgaW5jb21lX2NsZWFuZWRfYmMgPSBzYXQuZm9ybXVsYS5iYywgCiAgICAgICAgICAgICAgICAgaW5jb21lLmRhdGEuc3BsaXQuc2F0ID0gc2F0LmZvcm11bGEuYmMsIAogICAgICAgICAgICAgICAgIGluY29tZS5kYXRhLnNwbGl0LmJlc3QgPSBpbmNvbWUuYmVzdC5mb3JtdWxhLAogICAgICAgICAgICAgICAgIGluZHVzdHJ5X2NsZWFuZWQgPSBzYXQuZm9ybXVsYSwgCiAgICAgICAgICAgICAgICAgaW5kdXN0cnlfY2xlYW5lZF9iYyA9IHNhdC5mb3JtdWxhLmJjLCAKICAgICAgICAgICAgICAgICBpbmR1c3RyeS5kYXRhLnNwbGl0LnNhdCA9IHNhdC5mb3JtdWxhLmJjLCAKICAgICAgICAgICAgICAgICBpbmR1c3RyeS5kYXRhLnNwbGl0LmJlc3QgPSBpbmR1c3RyeS5iZXN0LmZvcm11bGEpCgphbGwuc3BsaXRzIDwtIGxpc3QoCiAgJ2luY29tZV9jbGVhbmVkJyA9IHRlc3RfdHJhaW5fc3BsaXQoaW5jb21lX2NsZWFuZWQsIGZvcm11bGFzW1snaW5jb21lX2NsZWFuZWQnXV0pLAogICdpbmNvbWVfY2xlYW5lZF9iYycgPSB0ZXN0X3RyYWluX3NwbGl0KGluY29tZV9jbGVhbmVkX2JjLCBmb3JtdWxhc1tbJ2luY29tZV9jbGVhbmVkX2JjJ11dKSwKICAnaW5jb21lLmRhdGEuc3BsaXQuc2F0JyA9IHRlc3RfdHJhaW5fc3BsaXQoaW5jb21lLmR1bW15LmJjLCBmb3JtdWxhc1tbJ2luY29tZS5kYXRhLnNwbGl0LnNhdCddXSksCiAgJ2luY29tZS5kYXRhLnNwbGl0LmJlc3QnID0gdGVzdF90cmFpbl9zcGxpdChpbmNvbWUuZHVtbXkuYmMsIGZvcm11bGFzW1snaW5jb21lLmRhdGEuc3BsaXQuYmVzdCddXSksCiAgJ2luZHVzdHJ5X2NsZWFuZWQnID0gdGVzdF90cmFpbl9zcGxpdChpbmR1c3RyeV9jbGVhbmVkLCBmb3JtdWxhc1tbJ2luZHVzdHJ5X2NsZWFuZWQnXV0pLAogICdpbmR1c3RyeV9jbGVhbmVkX2JjJyA9IHRlc3RfdHJhaW5fc3BsaXQoaW5kdXN0cnlfY2xlYW5lZF9iYywgZm9ybXVsYXNbWydpbmR1c3RyeV9jbGVhbmVkX2JjJ11dKSwKICAnaW5kdXN0cnkuZGF0YS5zcGxpdC5zYXQnID0gdGVzdF90cmFpbl9zcGxpdChpbmR1c3RyeS5kdW1teS5iYywgZm9ybXVsYXNbWydpbmR1c3RyeS5kYXRhLnNwbGl0LnNhdCddXSksCiAgJ2luZHVzdHJ5LmRhdGEuc3BsaXQuYmVzdCcgPSB0ZXN0X3RyYWluX3NwbGl0KGluZHVzdHJ5LmR1bW15LmJjLCBmb3JtdWxhc1tbJ2luZHVzdHJ5LmRhdGEuc3BsaXQuYmVzdCddXSkKKQoKI0ZvciBsb29wcyBpbml0aWFsaXphdGlvbgpuby5yZWcucjIgPC0gYygpIApsYXNzby5yZWcucjIgPC0gYygpCnJpZGdlLnJlZy5yMiA8LSBjKCkKCgpmb3IgKGkgaW4gbmFtZXMoYWxsLnNwbGl0cykpIHsKICAjbm8gcmVndWxhcml6YXRpb24KICBtID0gbG0oZm9ybXVsYXNbW2ldXSwgYWxsLnNwbGl0c1tbaV1dW1snZGF0YS50cmFpbiddXSkKICAjbm8ucmVnLnIyIDwtIGMobm8ucmVnLnIyLCBzdW1tYXJ5KG0pJGFkai5yLnNxdWFyZWQpCiAgeS5wcmVkaWN0ID0gcHJlZGljdChtLCBuZXdkYXRhID0gYXMuZGF0YS5mcmFtZShhbGwuc3BsaXRzW1tpXV1bWydYLnRlc3QnXV0pKQogIGFkai5SMiA8LSBldmFsX3Jlc3VsdHMoYWxsLnNwbGl0c1tbaV1dW1sneS50ZXN0J11dLCB5LnByZWRpY3QsIGFsbC5zcGxpdHNbW2ldXVtbJ2RhdGEudGVzdCddXSwgbGVuZ3RoKGNvZWYobSkpKVsnUnNxdWFyZSddCiAgbm8ucmVnLnIyIDwtIGMobm8ucmVnLnIyLCBhZGouUjIpCiAgCiAgI2xhc3NvIHJlZ3VsYXJpemF0aW9uCiAgbGFzc28ucmVnLnIyIDwtIGMobGFzc28ucmVnLnIyLCByZWd1bGFyaXphdGlvbl9mdW5jKGFsbC5zcGxpdHNbW2ldXSwgMSwgaSkpCiAgCiAgI3JpZGdlIHJlZ3VsYXJpemF0aW9uCiAgcmlkZ2UucmVnLnIyIDwtIGMocmlkZ2UucmVnLnIyLCByZWd1bGFyaXphdGlvbl9mdW5jKGFsbC5zcGxpdHNbW2ldXSwgMCwgaSkpCn0KCmBgYAoKCmBgYHtyfQpkZi5yc3F1YXJlIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoJ25vUmVnJyA9IG5vLnJlZy5yMiwgJ2xhc3NvUmVnJyA9IGxhc3NvLnJlZy5yMiwgJ3JpZGdlUmVnJyA9IHJpZGdlLnJlZy5yMikpCnJvd25hbWVzKGRmLnJzcXVhcmUpID0gbmFtZXMoYWxsLnNwbGl0cykKZGYucnNxdWFyZQpgYGAKCgpgYGB7cn0KIyBzYXQubW9kZWwuYmMgPC0gbG0oQXZnLmJjIH4uLCBkYXRhID0geHkuc3BsaXRzLnNhdFtbJ2luZHVzdHJ5J11dW1snZGF0YS50cmFpbiddXSkKIyAKIyB0ZW1wLmRmIDwtIGFzLmRhdGEuZnJhbWUoeHkuc3BsaXRzLnNhdFtbJ2luZHVzdHJ5J11dW1snWC50ZXN0J11dKQojIAojIGNvbG5hbWVzKHRlbXAuZGYpWzU3XQojIAojIGNvbG5hbWVzKHRlbXAuZGYpIDwtIHN0cl9yZXBsYWNlX2FsbChjb2xuYW1lcyh0ZW1wLmRmKSwgIltgXSIsICcnKQojIGNvbG5hbWVzKHRlbXAuZGYpCiMgCiMgeS5wcmVkaWN0IDwtIHByZWRpY3Qoc2F0Lm1vZGVsLmJjLCBuZXdkYXRhID0gdGVtcC5kZikKIyBNU0Uuc2F0IDwtIG1lYW4oKHkucHJlZGljdCAtIHh5LnNwbGl0cy5zYXRbWydpbmR1c3RyeSddXVtbJ3kudGVzdCddXSleMikKIyAKIyBwcmludChwYXN0ZShpLCAnIExhc3NvIE1TRTogJywgTVNFLmxhc3NvLCAnIFNhdHVyYXRlZCBNU0U6ICcsIE1TRS5zYXQpKQojIAojIHN1bW1hcnkoc2F0Lm1vZGVsLmJjKSRjb2VmZmljaWVudHMKIyBhcy5kYXRhLmZyYW1lKHh5LnNwbGl0cy5zYXRbWydpbmR1c3RyeSddXVtbJ1gudGVzdCddXSkgJT4lIHNlbGVjdChzdGFydHNfd2l0aCgnYEdyb3VwT3RoJykpCgpgYGAKCgpgYGB7cn0KIyBDYWxjdWxhdGUgUiBzcXVhcmVkIGZyb20gdHJ1ZSB2YWx1ZXMgYW5kIHByZWRpY3Rpb25zCmV2YWxfcmVzdWx0cyA8LSBmdW5jdGlvbih0cnVlLCBwcmVkaWN0ZWQsIGRmLCBwKSB7CiAgbiA9IG5yb3coZGYpCiAgYWRqLlJTUyA8LSBzdW0oKHByZWRpY3RlZCAtIHRydWUpXjIpLyhuLXAtMSkKICBhZGouVFNTIDwtIHN1bSgodHJ1ZSAtIG1lYW4odHJ1ZSkpXjIpLyhuLTEpCiAgYWRqLlJfc3F1YXJlIDwtIDEgLSBhZGouUlNTIC8gYWRqLlRTUwogICNSTVNFID0gc3FydChSU1MvbikKICAKICByZXR1cm4oYyhSc3F1YXJlID0gYWRqLlJfc3F1YXJlKSkKfQoKI2Zvcm11bGEgZm9yIGFkanVzdGVkIFJeMiBmb3VuZCBpbiBmb2xsb3dpbmcgbGluay4KI2h0dHBzOi8vd3d3LmdyYXBocGFkLmNvbS9ndWlkZXMvcHJpc20vbGF0ZXN0L2N1cnZlLWZpdHRpbmcvcmVnX2FkanVzdGVkLXItc3F1YXJlZC5odG0KYGBgCgoKCgoKCgoKQWRkaXRpb25hbCBDYWxjdWxhdGlvbnMKYGBge3J9CmFzLmRhdGEuZnJhbWUobGFzc28uYmVzdC5sYW1iZGEudHJhaW4ucHJlZCkgJT4lIG11dGF0ZShBdmdfaW5fZG9sbGFycyA9IChsYXNzby5iZXN0LmxhbWJkYS50cmFpbi5wcmVkKmxhbWJkYS5iYysxKV4oMS9sYW1iZGEuYmMpKQpgYGAKCmBgYHtyfQppbmNvbWUuc2F0LmRhdGEuc3BsaXQgPC0gdGVzdF90cmFpbl9zcGxpdChpbmNvbWUuZHVtbXkuYmMsIEF2Zy5iYyB+IC4pCmluY29tZS5zYXQuZGF0YS5zcGxpdFtbJ1gudHJhaW4nXV0KCnNhdC5tb2RlbC5iYyA8LSBsbShBdmcuYmMgfi4sIGRhdGEgPSBhcy5kYXRhLmZyYW1lKGNiaW5kKGluY29tZS5zYXQuZGF0YS5zcGxpdFtbJ1gudHJhaW4nXV0sIGluY29tZS5zYXQuZGF0YS5zcGxpdFtbJ3kudHJhaW4nXV0pKSkKc3VtbWFyeShzYXQubW9kZWwuYmMpCgpjYWxjX01TRShzYXQubW9kZWwuYmMsIGFzLmRhdGEuZnJhbWUoaW5jb21lLnNhdC5kYXRhLnNwbGl0W1snWC50ZXN0J11dKSwgaW5jb21lLnNhdC5kYXRhLnNwbGl0W1sneS50ZXN0J11dKQoKCnNhdC55LnByZWRpY3QgPC0gcHJlZGljdChzYXQubW9kZWwuYmMsIG5ld2RhdGEgPSBhcy5kYXRhLmZyYW1lKGluY29tZS5zYXQuZGF0YS5zcGxpdFtbJ1gudGVzdCddXSkpCm1lYW4oKHNhdC55LnByZWRpY3QgLSBpbmNvbWUuc2F0LmRhdGEuc3BsaXRbWyd5LnRlc3QnXV0pXjIpCmBgYAoK